# [ANN]: RxInfer.jl 2.0 Julia package for automated Bayesian inference on a factor graph with reactive message passing

Thank you, that is very helpful! So if I wanted to model a Gaussian Markov random field, say for example this simple one with four latent nodes (`a`-`d`) and two observations (`x` and `y`):

``````x
|
a---b
|   |
c---d---y

``````

what would be the correct way to specify it in the `@model` function?

To give a tiny bit of background, `RxInfer.jl` uses a particular type of factor graphs, which establishes the connection between the random variables. I will not go into details about the computational graph behind the package. Still, it technically means that if I want to implement your model, I need to add additional nodes (functions) in your graph representation.

For example, you can specify the graph as follows:

``````x
|
(f_x)
|
a---(f_a)---b
|           |
(f_a)       |
|           |
c--------(f_cb)--d--(f_d)--y
``````

The difference with your specification is that I explicitly show the functional dependence between your variables. The graph I showed is still incomplete, though I hope it will help you to understand what’s missing from the `RxInfer.jl` perspective when implementing your graph.

Now, depending on the functional form of `f`s (let’s say Gaussians, i.e., `f_i(i, x) = N(i|x, 1.0) i in {x, a, d}` and `f_cb=N(d|c+b, 1.0)`) you can write the model and inference in `RxIner.jl` as:

``````using RxInfer

@model function loopy_model()

y   = datavar(Float64)
x_0 = datavar(Float64)

# variances are chosen arbitrary
x ~ Normal(mean = x_0, var = 1.0)
a ~ Normal(mean = x, var = 1.0)   # f_x
b ~ Normal(mean = a, var = 1.0)   # f_a
c ~ Normal(mean = a, var = 1.0)   # f_a
d ~ Normal(mean = c+b, var = 1.0) # f_cb

y ~ Normal(mean = d, var = 1.0)
end

result = inference(
model = loopy_model(),
data = (y = 1.0, x_0=1.0),
initmessages = (
a = vague(NormalMeanPrecision),
),
iterations = 50,
free_energy = true
)
``````

@model macro lets you specify the model in a probabilistic way, `RxInfer.jl` handles the graphical equivalent of the model under the hood for fast computations.

2 Likes

So if I’m understanding the modeling language correctly, the left-hand side of each `~` is a node, and each node can only appear in one `~` statement. The right-hand side of each `~` corresponds to a factor. If a node has more than one edge coming into it, it needs to be explicitly written as a function of all the connected nodes. So a graph like this

``````x---a   b---y
\ /
d
|
c
|
z
``````

could be specified like this:

``````x = datavar(Float64)
y = datavar(Float64)
z = datavar(Float64)
# v is arbitrary
a ~ Normal(x, v)
b ~ Normal(y, v)
c ~ Normal(z, v)
d ~ Normal((a + b + c) / 3, v)
``````

Is that right?

`RxInfer.jl` uses Forney-style Factor Graphs (FFGs) as the graphical representation of the generative model. We use edges to represent variables and nodes for factors/functions. Indeed, you can think of the left-hand side of ~ as a variable defined by an edge (or a node in your description/ it really doesn’t matter for now). The right-hand side of ~ is indeed a factor.

If a node has more than one edge coming into it (in the case of a multi-argument function), you would need to pass all the required variables inside the function.

For example, if you have a gaussian factor node `N(y|x, z)`, it has three edges for out `y`, mean `x`, and variance `z`. In your model definition, you would have to write something like this:

``````...
y ~ Normal(mean=x, variance=z)
...
``````

As for the model you have specified, yes, that could be an option.