Inference lifecycle

Every inference computation in ReactiveMP.jl goes through three phases: construction, activation, and observation. Understanding these phases is essential when working directly with the engine.

Note

If you are using ReactiveMP.jl through RxInfer.jl, these phases are managed for you automatically by the infer function. This page is aimed at users working with the low-level API directly.

Phase 1: Construction

In the construction phase, you create the variables and factor nodes of your model and connect them together.

Variables are created with one of three constructors depending on their role:

x = randomvar()   # latent variable — will be inferred
y = datavar()     # observed quantity — will receive data
c = constvar(2.0) # fixed constant — never changes

See Variables for a full description of each type.

Factor nodes are connected to variables using the make_node machinery (typically called by a model specification layer). Each connection registers the variable with the node and allocates a ReactiveMP.MessageObservable stream for that edge. At this point, all streams are lazy — they exist as placeholders but are not yet computing anything.

After construction, the graph looks like this conceptually:

  [datavar: y] ──── [factor: f] ──── (randomvar: x)
                     unconnected         unconnected
                     streams             streams
Note

The degree of a variable (number of connected factors) is determined during construction. Adding connections after activation is not supported.

Phase 2: Activation

Activation wires the lazy observable streams into a live reactive network. This is done by calling ReactiveMP.activate! on each variable and factor node, passing an options object that bundles inference-time configuration.

For factor nodes, activation is driven by ReactiveMP.FactorNodeActivationOptions, which carries:

  • The factorization assumption (mean-field, structured, or full BP).
  • An optional stream postprocessor applied to outbound message, marginal, and score streams (e.g. for scheduling).
  • Metadata and approximation method settings.

For variables, activation is driven by ReactiveMP.RandomVariableActivationOptions or ReactiveMP.DataVariableActivationOptions, which wire up the marginal stream and prediction stream.

After activation, the graph is live:

  [datavar: y] ──── [factor: f] ──── (randomvar: x) ──► marginal q(x)
       ▲               rules                streams
  (waiting for         connected            connected
   observations)

Every edge now carries a ReactiveMP.MessageObservable that is subscribed to its upstream sources. The marginal at x is connected to a ReactiveMP.MarginalObservable that will emit updated beliefs every time a message changes.

Phase 3: Observation

Once the graph is activated, inference is driven by feeding data into the data variables using new_observation!:

new_observation!(y, 3.14)

This call pushes a new Message wrapping a PointMass(3.14) into the data variable's outbound stream. The change propagates reactively through all connected factor nodes, triggering rule computations, which in turn push updated messages to downstream variables, which update their marginals.

The result is that subscribing to the marginal stream of x yields updated posterior beliefs automatically:

  new_observation!(y, 3.14)
         │
         ▼
  [datavar: y] ──► message ──► [factor: f] ──► message ──► (randomvar: x)
                                                                  │
                                                                  ▼
                                                           marginal q(x) emits

You can subscribe to the marginal stream of any RandomVariable to receive updated beliefs:

subscribe!(get_stream_of_marginals(x), (marginal) -> println("Updated: ", mean(marginal)))

Multiple calls to new_observation! are possible after activation — each one triggers another round of reactive propagation. This makes the engine suitable for streaming/online inference scenarios.

Summary

PhaseWhat happensKey functions
ConstructionVariables and nodes created, edges connected, streams allocated (lazy)randomvar, datavar, constvar, @node
ActivationLazy streams wired into a live reactive networkReactiveMP.activate!, ReactiveMP.FactorNodeActivationOptions
ObservationData fed in, messages propagate, marginals updatenew_observation!, ReactiveMP.get_stream_of_marginals

Next steps

  • Factor nodes — how nodes are implemented and activated.
  • Variables — stream creation and activation details for each variable type.
  • Callbacks — how to hook into message and marginal computation events.
  • Custom functional form — constraining the functional form of marginals during inference.