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

**URL:** <https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879>\
**Category:** Package Announcements\
**Tags:** reactiveprogramming, distributions, bayesian-inference, reactivemp, rxinfer\
**Created:** [November 7, 2022, 1:49pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879 "2022-11-07T13:49:56Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [November 7, 2022, 1:49pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/1 "2022-11-07T13:49:56Z")

</div>

![rxinfer_black](https://global.discourse-cdn.com/julialang/original/3X/e/e/ee6ad90d772ec76d84f34591543dbb497c8ba6b0.png)

We are excited to announce the release of [RxInfer 2.0](https://biaslab.github.io/rxinfer-website/), which is a Julia package for fast and scalable Bayesian inference in probabilistic models. `RxInfer` unites previously released packages `ReactiveMP`, `GraphPPL`, and `Rocket` in a single user-friendly ecosystem that aims to execute efficient Bayesian inference in real-time.`GraphPPL` is a package for user-friendly model and inference constraints specification. `ReactiveMP` exports a high-performant, reactive message passing-based Bayesian inference engine for the specified model. The reactive extensions package `Rocket` supports running Bayesian inference on streaming data sets in real-time.

In general, `RxInfer` executes inference faster than sampling-based Bayesian inference methods since it exploits local conjugate pairings in the graph representation of a probabilistic model. For instance, `RxInfer` significantly outperforms Julia’s state-of-the-art inference package `Turing` on a set of conjugate state-space models. `Turing`, on the other hand, may be able to execute inference for a less constrained set of models. However, the `ReactiveMP` inference engine has evolved significantly over the last year and is capable of running inference for many non-conjugate models as well. It is also possible to include non-linear dependencies between variables and use various built-in approximation methods, such as Statistical Linearization, Unscented transform and Conjugate-computation Variational Inference (CVI).

In short, `RxInfer` provides:

- A convenient user-friendly language for specification of model and inference constraints:

- Inference for static large datasets with millions of observations on a standard (win/mac/linux) laptop.

- Real-time inference for streaming data sets with potentially an unlimited number of observations

- A unified framework for different Bayesian inference algorithms, including:

- Hybrid Bayesian inference algorithms across different parts of the probabilistic model’s graph

- `RxInfer` is easily extendable with custom novel factor nodes and message update equations

- Supports automatic differentiation of the entire inference procedure for global parameters tuning

- Bethe Free Energy (approximation to the Bayesian model evidence) evaluation

- And much more!

Check the [Getting started](https://biaslab.github.io/RxInfer.jl/stable/manuals/getting-started/) section to get started. The documentation has a lot of [example and tutorials](https://biaslab.github.io/RxInfer.jl/stable/examples/overview/).

Links:

- RxInfer website: [RxInfer.jl](https://biaslab.github.io/rxinfer-website/)
- RxInfer GitHub: [GitHub - biaslab/RxInfer.jl: Julia package for automated Bayesian inference on a factor graph with reactive message passing](https://github.com/biaslab/RxInfer.jl)
- RxInfer Documentation: [Home · RxInfer.jl](https://biaslab.github.io/RxInfer.jl/stable/)
- ReactiveMP.jl: [GitHub - biaslab/ReactiveMP.jl: High-performance reactive message-passing based Bayesian inference engine](https://github.com/biaslab/ReactiveMP.jl)
- GraphPPL.jl: [GitHub - biaslab/GraphPPL.jl: DSL for probabilistic models specification and probabilistic programming.](https://github.com/biaslab/GraphPPL.jl)
- Rocket.jl: [GitHub - biaslab/Rocket.jl: Functional reactive programming extensions library for Julia](https://github.com/biaslab/Rocket.jl)

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [November 7, 2022, 2:17pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/2 "2022-11-07T14:17:15Z")

</div>

This seems like a very cool package, congratulations on the work!

I have a question regarding the model on the front-page:

```julia
@model function SSM(n, x0, A, B, Q, P) 
 
 	 # x is a sequence of hidden states 
 	 x = randomvar(n) 
 
 	 # y is a sequence of clamped observations 
 	 y = datavar(Vector{Float64}, n) 
 
 	 # `~` expression creates a probabilistic relationship
 	 # between random variables
 	 x_prior ~ MvNormal(μ = mean(x0), Σ = cov(x0)) 
 	 x_prev = x_prior 
 
 	 # Build the state-space model 
 	 for i in 1:n 
 		   x[i] ~ MvNormal(μ = A * x_prev, Σ = Q) 
 		   y[i] ~ MvNormal(μ = B * x[i], Σ = P) 
 		   x_prev = x[i] 
 	 end 
 end 

```

In particular, I’m wondering how to interpret covariance-properties of the variables defined by the line

```julia
x[i] ~ MvNormal(μ = A * x_prev, Σ = Q) 

```

Here, `x_prev` is a random variable with some distribution attached to it, so the mean of `x[i]` will be a random variable. How does this relate to the `Q` that is specified as the covariance of `x[i]`? Is covariance `Q` _added_ to the covariance of `A * x_prev` in the sense that A x\_{prev} + w where w \sim N(0, Q)? This would correspond to how I normally think of, e.g., a Kalman filter operating, but it visually conflicts a bit with stating that x\_i \sim N(A x\_{prev}, Q). Maybe this line has a different interpretation in this language?

---

<div class="post-metadata">

**Author:** ![albertpod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertpod/32/31336_2.png) [@albertpod](https://discourse.julialang.org/u/albertpod)\
**Post date:** [November 7, 2022, 3:06pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/3 "2022-11-07T15:06:54Z")

</div>

Hi @baggepinnen!

Thanks for the question. If `w[i]~N(0, Q)`, then we can marginalize out its mean, which is zero, hence  
`x[i] = A*x_prev + w[i]` can be rewritten as `MvNormal(μ=A*x_prev, Σ=Q)`  
Alternatively, you can specify the model in KF-like way:

```julia
@model function SSM(n, x0, A, B, Q, P) 
 
    # x is a sequence of hidden states 
    w = randomvar(n) 
    x = randomvar(n) 

    # y is a sequence of clamped observations 
    y = datavar(Vector{Float64}, n) 

    # `~` expression creates a probabilistic relationship
    # between random variables
    x_prior ~ MvNormal(μ = mean(x0), Σ = cov(x0)) 
    x_prev = x_prior 

    # Build the state-space model 
    for i in 1:n
          w[i] ~ MvNormal(μ=zeros(length(mean(x0))), Σ=Q)
          x[i] ~ A * x_prev + w[i]
          y[i] ~ MvNormal(μ = B * x[i], Σ = P) 
          x_prev = x[i] 
    end 
end

```

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [November 7, 2022, 3:15pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/4 "2022-11-07T15:15:35Z")

</div>

Good question @baggepinnen ! I see that @albertpod has already replied to you, I can just add that you are right and basically:

```julia
x[i] ~ N(A * x[i - 1], Q)

```

is a shorthand for

```julia
tmp ~ A * x[i - 1]
x[i] ~ N(tmp, Q)

```

which (thanks to the Gaussian distribution statistical properties) can be rewritten exactly like

```julia
tmp ~ A * x[i - 1]
w ~ N(0, Q)
x[i] ~ tmp + w

```

Referring to you original question the covariance matrix for variable `x[i]`. If we assume that the covariance matrix for `x[i - 1]` is \Sigma\_{i - 1} than \Sigma\_{i} = A \Sigma\_{i - 1} A^T + Q (following equations from Sascha Korl, A Factor Graph Approach to Signal Modelling, System Identification and Filtering)

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [November 7, 2022, 5:09pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/5 "2022-11-07T17:09:20Z")

</div>

Thanks for your comments guys!

What’s confusing me is probably that

```julia
x[i] ~ MvNormal(μ = A * x_prev, Σ = Q) 

```

looks like `x[i]` is sampled from a normal distribution with covariance `Q`, but in fact, the covariance of `x[i]` is \Sigma\_i from the Lyapunov iteration \Sigma\_i = A \Sigma\_{i-1} A^T + Q.

In either case, I now understand how your modeling language works. Keep up the nice work! 🙂

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [November 9, 2022, 8:13am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/6 "2022-11-09T08:13:40Z")

</div>

Looks great. Can you share more about where it should excel and where sampling based methods should be preferred? Are there a guidelines for that?

---

<div class="post-metadata">

**Author:** ![albertpod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertpod/32/31336_2.png) [@albertpod](https://discourse.julialang.org/u/albertpod)\
**Post date:** [November 9, 2022, 12:57pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/7 "2022-11-09T12:57:41Z")

</div>

Hi @RoyiAvital!

Great question! Indeed there are no written guidelines for that at the moment.

Generally, if you can exploit conjugacy (or conditional-conjugacy) in your model or if there are pre-defined nodes that serve your needs, for example, [Gamma Mixture node](https://biaslab.github.io/RxInfer.jl/stable/examples/Gamma%20Mixture/) or [GCV node](https://biaslab.github.io/RxInfer.jl/stable/examples/Hierarchical%20Gaussian%20Filter/), then you will excel by using `RxInfer.jl` in terms of **accuracy** and **speed**!

Most of these nodes representing distributions can be easily combined, e.g., `Gamma Mixture` can serve as a prior for the precision parameter of `Normal` distribution.

However, we recognize that sometimes you may want to put `Beta` prior on top of the mean of the `Normal` distribution. In this case, we advise using the CVI algorithm that uses sampling because there is no analytical solution. Note the [CVI approximation](https://biaslab.github.io/RxInfer.jl/stable/examples/Conjugate-Computational%20Variational%20Message%20Passing/) will be employed locally; the rest of the inference will try to use analytical updates (if possible). Advanced users, can implement the local _more efficient_ update for this scenario.

In a situation where your model consists only of “non-standard” dependencies, which can be solved only through sampling, you can, in principle, run inference by solely using CVI or Unscented approximations. Though, CVI will not be fast.

We will add more examples highlighting the advantage of the `RxInfer.jl` approach.

If you have more concrete questions, we will be happy to answer them.

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [November 9, 2022, 1:11pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/8 "2022-11-09T13:11:21Z")

</div>

So if I get you write there are 3 cases:

1. Model based on Conjugacy  
In this case `RxInfer.jl` will be (Almost?) as efficient as using the explicit formulas for the conjugate priors. But if one wants, probably one can do it manually.
2. Model without Any Conjugacy  
In this case sampling based methods are the way to go.
3. Mixed Model  
In this case `RxInfer.jl` also should have advantage as it can use the local cases where conjugacy can be exploited.

In case (3) the question is how efficient are the sampling mechanism in `RxInfer.jl`. If they are as efficient as competitions it will be uniformly the best choice in this case. If not, it will depend on the specific case and balance between the cases.

---

<div class="post-metadata">

**Author:** ![albertpod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertpod/32/31336_2.png) [@albertpod](https://discourse.julialang.org/u/albertpod)\
**Post date:** [November 9, 2022, 2:42pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/9 "2022-11-09T14:42:32Z")

</div>

It’s pretty hard to provide a general recipe on what to do even within these 3 cases.

1. Model based on Congugacy:

So, even if your model exhibits conjugacy, the inference might be problematic. So manual derivation of update rules will not be as easy as it may seem. Under the hood, `RxInfer.jl` casts your probabilistic model into the computational graph, Forney-style Factor Graph (FFG). FFG has a one-to-one correspondence with your probabilistic model. If there are loops in your graph, you would typically need a schedule for updates, even in conjugate cases.  
_**The unique feature of `RxInfer` is that it is based on a reactive programming framework: there is no fixed inference algorithm. The model is broken into a network of factors (nodes), and each node independently processes incoming data streams.**_  
It lets you iterate fast through your model and inference and frees you from manual derivations of the inference algorithm.

1. Model without Any Conjugacy:

> [@RoyiAvital](#):
>
> In this case, sampling based methods are the way to go.

Generally, yes; however, if you can get around with `Unscented` transform or `Linearization` and you crave speed, then we advise using these techniques. Despite the naming, `CVI` approximation can handle many non-conjugate scenarios, but this method requires more examples. We plan to add more advanced and faster approximations to deal with different intractabilities.

1. Mixed Model

> [@RoyiAvital](#):
>
> In case (3) the question is how efficient are the sampling mechanism in `RxInfer.jl`. If they are as efficient as competitions it will be uniformly the best choice in this case. If not, it will depend on the specific case and balance between the cases.

Let me put it straight, `RxInfer.jl` does not have a sole sampling-based inference mechanism like [Turing.jl](https://turing.ml/stable/), e.g. `HMC`, `SMC`, etc. We will add this feature later, probably we will just integrate `Turing.jl` into our package. However, `RxInfer.jl` has sampling elements in the `CVI` method that is used for the `Delta` node.

---

<div class="post-metadata">

**Author:** ![stanlazic](https://avatars.discourse-cdn.com/v4/letter/s/ce73a5/32.png) [@stanlazic](https://discourse.julialang.org/u/stanlazic)\
**Post date:** [November 18, 2022, 8:10pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/10 "2022-11-18T20:10:50Z")

</div>

This looks great! I’m trying to run a multiple regression analysis based on the linear regression example but can’t figure out how to use matrix multiplication. This works:

```julia
# generate data
xdata1 = randn(10)
xdata2 = randn(10)
ydata = 2 .* xdata1 .+ 3 .* xdata2 .+ randn(10)

# define model
@model function linear_regression(n)
    x = datavar(Float64, (n, 2))
    y = datavar(Float64, n)

    # priors
    β0 ~ NormalMeanVariance(0.0, 100.0)
    β = randomvar(2)
    β .~ NormalMeanVariance(0.0, 1.0)
    
    for i in 1:n       
        y[i] ~ NormalMeanVariance(β[1] * x[i, 1] + β[2] * x[i, 2] + β0, 1.0)
        # I was expecting something like this to work:
        # y[i] ~ NormalMeanVariance(dot(x[i, :], β) + β0, 1.0)
    end
end

# run inference
results = inference(
    model = linear_regression(length(xdata1)), 
    data = (y = ydata, x = hcat(xdata1, xdata2)), 
    initmessages = (β = NormalMeanVariance(0.0, 1.0),
                    β0 = NormalMeanVariance(0.0, 1.0))
)

```

When using matrix multiplication I get `MethodError: no method matching make_node(::typeof(dot)`. And similar error messages when I try transpose(), or '.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [November 19, 2022, 2:03am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/11 "2022-11-19T02:03:53Z")

</div>

Thanks for the contribution, this looks great! I have two questions:

1. Is there a public non-macro interface? If not, can we get one? 🙂
2. Would you consider renaming the package to ReactiveInfer? The “Rx” is a bit cryptic, and “Rx” is a common abbreviation for “prescription” (as in a medical prescription).

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [November 19, 2022, 11:42am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/12 "2022-11-19T11:42:33Z")

</div>

Hey @stanlazic !

Thank you for the interest in `RxInfer`. For your example to work you need to slightly modify your model and input data in the following way:

```julia
# define model
@model function linear_regression(n)
    # I changed x to be of the vector type
    x = datavar(Vector{Float64}, n)
    y = datavar(Float64, n)

    # priors
    β0 ~ NormalMeanVariance(1.0, 100.0)
    # I changed beta to be of the multivariate type
    β ~ MvNormalMeanCovariance([0.0, 0.0], [1.0 0.0; 0.0 1.0])
    
    for i in 1:n       
        y[i] ~ NormalMeanVariance(dot(x[i], β) + β0, 1.0)
    end
end

```

and the inference:

```julia
xdata = collect.(zip(xdata1, xdata2)) # collect into pairs

results = inference(
    model = linear_regression(length(xdata1)), 
    data = (y = ydata, x = xdata), 
    initmessages = (β0 = NormalMeanVariance(0.0, 1.0), )
)

```

and the results will be available:

```julia
mean_cov(results.posteriors[:β])

```

```julia
([1.1638631582255687, 2.1389045170632293], [0.24982928559123693 0.07513981828561604; 0.07513981828561604 0.21513388551908566])

```

The reason for your error is that `dot` is not defined between two vectors of `RandomVariable`s, but rather between two multivariate `RandomVariable`s.

You may also be interested in the following example: [ReactiveMP: How to run linear model with multiple predictors and an intercept - #6 by albertpod](https://discourse.julialang.org/t/reactivemp-how-to-run-linear-model-with-multiple-predictors-and-an-intercept/85290/6). This example uses old version of the `RxInfer`, which we called `ReactiveMP`. But the example itself should work in any case if you remove `[default_factorisation = MeanField()] ` from the `@model` specification and put it in the `inference()` function as follows:

```julia
n = 250
m = 100

@model function multivariate_linear_regression(n,m)
    a ~ MvNormalMeanCovariance(zeros(m), diagm(ones(m)))
    b ~ NormalMeanVariance(0.0,1.0)
    W ~ InverseWishart(n+2, diageye(n))
    c ~ ones(n)*b
    x = datavar(Matrix{Float64})
    y = datavar(Vector{Float64})
    z ~ x*a+c
    y ~ MvNormalMeanCovariance(z, W)

end

results = inference(
    model = multivariate_linear_regression(n,m),
    data = (y = randn(n), x = randn(n,m)),
    initmarginals = (W = InverseWishart(n+2, diageye(n)), ),
    returnvars = (a = KeepLast(), b = KeepLast(), W = KeepLast()),
    free_energy = true,
    iterations = 10,
    constraints = MeanField()
)

```

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [November 19, 2022, 11:51am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/13 "2022-11-19T11:51:49Z")

</div>

Hey @CameronBieganek ! Thanks for your interest!

1. No, there is none. The `@model` macro is rather old already (previously we used it with `ReactiveMP.jl` library directly). Recently we have prioritised plans on refactoring this part including adding a public non-macro interface for model specification (such that models can be created on the fly or loaded from a file). We cannot provide any definite time frame on when it could be ready though. So at some point you will get one 🙂
2. The reason for `Rx` was to associate with the `Reactive eXtensions` family of libraries here: [ReactiveX - Languages](https://reactivex.io/languages.html). We considered that confusion when choosing a name for the library, but AFAIK `Rx` is a common abbreviation only in the US and is far less known outside of the US (I might be wrong though).

---

<div class="post-metadata">

**Author:** ![stanlazic](https://avatars.discourse-cdn.com/v4/letter/s/ce73a5/32.png) [@stanlazic](https://discourse.julialang.org/u/stanlazic)\
**Post date:** [November 20, 2022, 12:31am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/14 "2022-11-20T00:31:47Z")

</div>

I got it working – many thanks for your help!

---

<div class="post-metadata">

**Author:** ![Mark\_Ettinger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mark_ettinger/32/32833_2.png) [@Mark\_Ettinger](https://discourse.julialang.org/u/Mark_Ettinger)\
**Post date:** [December 7, 2022, 10:04pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/15 "2022-12-07T22:04:16Z")

</div>

In a model definition, how do I perform non-trivial calculations on a random variable for use as a parameter in another distribution. I’d like to use intermediate variables but it doesn’t seem possible. For example this works:

```julia
x ~ Normal(0, 1)
y ~ Normal(3 * x + 1, 1)

```

but this does not:

```julia
x ~ Normal(0, 1)
a = 3 * x + 1
y ~ Normal(a, 1)

```

I’d like to use the second form as, unlike in the simple case above, I’m not sure how to express my calculation in a closed form without introducing intermediary variables.

Thank you in advance!

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [December 8, 2022, 8:41am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/16 "2022-12-08T08:41:22Z")

</div>

Hey @Mark_Ettinger ,

thanks for your interest. You can use the second form if you replace `=` with `~`:

```julia
x ~ Normal(0, 1)
a ~ 3 * x + 1
y ~ Normal(a, 1)

```

Unlike other PPL, RxInfer [uses](https://biaslab.github.io/RxInfer.jl/stable/manuals/model-specification/) `~` to model deterministic dependencies between random variables. The reason for this behaviour is that the model specification language needs to distinguish between probabilistic expressions and normal Julia expressions. There is no sampling involved and technically `x` is not a number and you cannot use it in regular julia expression, but only in probabilistic expression with `~`.

As a consequence you cannot use random variables in indexing expressions or in control flow operations, as these are normal Julia expressions, like this is not allowed:

```julia
x ~ Normal(0, 1) 
if x > 0 # not allowed
...
end

```

---

<div class="post-metadata">

**Author:** ![Mark\_Ettinger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mark_ettinger/32/32833_2.png) [@Mark\_Ettinger](https://discourse.julialang.org/u/Mark_Ettinger)\
**Post date:** [December 8, 2022, 1:23pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/17 "2022-12-08T13:23:45Z")

</div>

Thanks @bvdmitri, your explanation helps a lot! But this doesn’t seem to work:

```julia
x ~ Normal(mean = 0, precision = 1)
y ~ 2 ^ x

```

Is exponentiation not implemented or I am doing something foolish?

(p.s. I’m not only new to RxInfer but also rather new to Julia)

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [December 9, 2022, 7:35am UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/18 "2022-12-09T07:35:36Z")

</div>

@Mark_Ettinger you do everything correctly, but for arbitrary functions over distribution you need to use non-linear function approximation methods. By default RxInfer performs analytical inference only with a few operators (like, `+`, `-`, `dot`, etc…). If you want to use arbitrary function in your model specification I would suggest you, first, to call it somehow, for example `f` and create the `@meta` specification with a specific approximation method:

```julia
f(x) = 2 ^ x

@model function mymodel()
    ...
    x ~ Normal(mean = 0, precision = 1)
    y ~ f(x)
end

@meta function mymeta()
    f() -> Linearization
    # Other available methods are Unscented and CVI
end

result = inference(
   model = mymodel(),
   meta = mymeta(),
   ...
)

```

you can also apply an approximation method in place, which might be even more convenient in some situations:

```julia
y ~ f(x) where { meta = Linearization() }

```

RxInfer will perform analytical inference where possible and fallback to the approximation method where needed.

More examples are available in the documentation:

- [Nonlinear pendulum inference](https://biaslab.github.io/RxInfer.jl/stable/examples/Nonlinear%20Noisy%20Pendulum/)
- [Rabbit population](https://biaslab.github.io/RxInfer.jl/stable/examples/Nonlinear%20Rabbit%20Population/)
- [Virus spread](https://biaslab.github.io/RxInfer.jl/stable/examples/Nonlinear%20Virus%20Spread/)
- [Sensor fusion](https://biaslab.github.io/RxInfer.jl/stable/examples/Nonlinear%20Sensor%20Fusion/)
- [Invertible NN](https://biaslab.github.io/RxInfer.jl/stable/examples/Invertible%20Neural%20Network%20Tutorial/)

P.S. All arguments to `f` must be random variables, this `y ~ f(x, 2)` is not possible at the moment, but should be available in the future.

---

<div class="post-metadata">

**Author:** ![ElOceanografo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eloceanografo/32/624_2.png) [@ElOceanografo](https://discourse.julialang.org/u/ElOceanografo)\
**Post date:** [January 24, 2023, 8:46pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/19 "2023-01-24T20:46:34Z")

</div>

Thanks for this package, it looks really cool. I was wondering if there’s a way to fit models on undirected and/or loopy graphs (for example, like the first visualization in [this tutorial](https://gaussianbp.github.io/))? If so, what’s the right way to specify those structures within a `@model`?

---

<div class="post-metadata">

**Author:** ![bvdmitri](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bvdmitri/32/22935_2.png) [@bvdmitri](https://discourse.julialang.org/u/bvdmitri)\
**Post date:** [January 24, 2023, 9:03pm UTC](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879/20 "2023-01-24T21:03:38Z")

</div>

Hey @ElOceanografo,

Graphs in `RxInfer` are undirected (in fact we don’t even have a notion of direction in the inference data structures). There are also no problems with running inference in loopy graphs, but for that you will need to initialise messages. The inference function supports the `initmessages` keyword arguments precisely for this.

You can take a look at the [Linear regression](https://biaslab.github.io/RxInfer.jl/stable/examples/Linear%20Regression/#examples-bayesian-linear-regression) example, which uses loopy Belief propagation and uses the `initmessages` keyword.

The `@model` macro works in such a way that `~` simply creates a link between variables with a given factor. So you can even write something like

```julia
@model function loopy_model()
    x = randomvar()
    y = randomvar()

    # This two statements create an obvious loop
    x ~ Normal(mean = y, var = 1.0)
    y ~ Normal(mean = x, var = 1.0)

    z = datavar(Float64)
    
    z ~ Normal(mean = x + y, var = 1.0)
end

```

And later on the inference

```julia
result = inference(
    model = loopy_model(),
    data = (z = 1.0, ),
    # The inference will throw an error without the `initmessages`
    initmessages = (
        x = vague(NormalMeanPrecision),
    ),
)

```

Be aware, however, that loopy belief propagation usually requires many iterations to converge (and for some models it does not converge at all, there are no convergency guaranties for loopy belief propagation). By default, the `inference` function performs only `1` iteration. This can be controlled with the `iterations` keyword argument. You may also be interested in the convergency metric with the `free_energy = true` argument as follows:

```julia
result = inference(
    model = loopy_model(),
    data = (z = 1.0, ),
    initmessages = (
        x = vague(NormalMeanPrecision),
    ),
    iterations = 100,
    free_energy = true
)

```

In my case it gives me the following output:

```julia
Inference results:
  Posteriors | available for (y, x)
  Free Energy: | Real[14.6851, 13.992, 13.2988, 12.6057, 11.9126, 11.2194, 10.5263, 9.83311, 9.13997, 8.44682 … 1.75593, 1.75593, 1.75593, 1.75593, 1.75593, 1.75593, 1.75593, 1.75593, 1.75593, 1.75593]

```

I can see that for this example the Free Energy values did indeed converge to a stable point.

[Next page](https://discourse.julialang.org/t/ann-rxinfer-jl-2-0-julia-package-for-automated-bayesian-inference-on-a-factor-graph-with-reactive-message-passing/89879.md?page=2)
