Callbacks in the Message Passing Procedure

ReactiveMP provides a way to "hook" into the message passing procedure and listen to various events via "callbacks". This can be useful, for example, to debug messages or monitor the order of computations.

ReactiveMP.EventType
Event{E}

Abstract supertype for all callback events in the reactive message passing procedure. E is a Symbol that identifies the event, e.g. Event{:before_message_rule_call}.

Concrete event types should subtype Event{:event_name} and carry the relevant data as fields. The naming convention is that for an event :event_name, the corresponding struct is called EventNameEvent.

See also: ReactiveMP.invoke_callback, ReactiveMP.handle_event

source
ReactiveMP.event_nameFunction
event_name(::Type{<:Event{E}}) where {E}
event_name(event::Event)

Returns the event name symbol E from an Event{E} type, subtype, or instance.

source
ReactiveMP.handle_eventFunction
handle_event(handler, event::Event)

Custom callback handlers should implement handle_event to listen to events during the reactive message passing procedure. Each event is a subtype of ReactiveMP.Event{E} that carries the relevant data as fields. The return value of handle_event is ignored. To communicate state changes, use mutable event fields.

julia> struct MyEvent <: ReactiveMP.Event{:my_event}
           value::Int
       end;

julia> struct MyCustomCallbackHandler end;

julia> ReactiveMP.handle_event(::MyCustomCallbackHandler, event::MyEvent) = print("Event value: $(event.value)");

See also: ReactiveMP.Event, ReactiveMP.invoke_callback, ReactiveMP.merge_callbacks

source
ReactiveMP.invoke_callbackFunction
invoke_callback(callbacks, event::Event)

Invokes the callback handler(s) for the given event and returns the event itself. Internally dispatches to ReactiveMP.handle_event for each handler. Does nothing and returns the event if callbacks is nothing.

See also: ReactiveMP.handle_event, ReactiveMP.Event, ReactiveMP.merge_callbacks

source
invoke_callback(callbacks::NamedTuple, event::Event{E})

The callbacks can also be a NamedTuple with fields corresponding to event names. Each callback function receives the event object itself. The return value of the callback is ignored.

julia> mutable struct CountEvent <: ReactiveMP.Event{:count_event}
           count::Int
       end;

julia> callbacks = (count_event = (event) -> event.count += 1,);

julia> event = CountEvent(0);

julia> ReactiveMP.invoke_callback(callbacks, event);

julia> event.count
1

If the NamedTuple does not have a field corresponding to the event name, the event will be ignored.

source
invoke_callback(callbacks::Dict{Symbol}, event::Event{E})

The callbacks can also be a Dict{Symbol, Any} with keys corresponding to event names. Works the same as the NamedTuple variant, but allows dynamic construction of callback handlers at runtime. Each callback function receives the event object itself. The return value of the callback is ignored.

If the Dict does not have a key corresponding to the event name, the event will be ignored.

source
invoke_callback(handler, event::Event)

Fallback for custom callback handlers. Delegates to ReactiveMP.handle_event and returns the event. Custom handlers should implement handle_event(handler, event) rather than invoke_callback.

source
invoke_callback(merged::MergedCallbacks, event::Event)

A specialized version of ReactiveMP.invoke_callback for ReactiveMP.MergedCallbacks. Calls the provided callbacks in order. Returns the event after all handlers have been invoked.

source
ReactiveMP.merge_callbacksFunction
merge_callbacks(callbacks_handlers...)

This function accepts an arbitrary amount of callback handlers and merges them together. Some callback handlers may or may not react on certain types of events.

julia> struct PrintEvent <: ReactiveMP.Event{:print_event}
           label::String
       end;

julia> handler1 = (print_event = (event) -> println("Handler 1: ", event.label),);

julia> handler2 = (print_event = (event) -> println("Handler 2: ", event.label),);

julia> merged_handler = ReactiveMP.merge_callbacks(handler1, handler2);

julia> ReactiveMP.invoke_callback(merged_handler, PrintEvent("hello"));
Handler 1: hello
Handler 2: hello

See also: ReactiveMP.invoke_callback, ReactiveMP.handle_event

source

Event naming convention

Every event in ReactiveMP is a concrete subtype of ReactiveMP.Event{E} where E is a Symbol identifying the event. The naming convention is straightforward: for an event identified by the symbol :event_name, the corresponding struct is called EventNameEvent. For example:

SymbolStruct
:before_message_rule_callReactiveMP.BeforeMessageRuleCallEvent
:after_product_of_two_messagesReactiveMP.AfterProductOfTwoMessagesEvent
:before_form_constraint_appliedReactiveMP.BeforeFormConstraintAppliedEvent

Each event struct carries the relevant data as fields, so you can inspect what happened during inference. You can use ReactiveMP.event_name to retrieve the symbol from any event type:

ReactiveMP.event_name(ReactiveMP.BeforeProductOfTwoMessagesEvent)
:before_product_of_two_messages

To see which fields an event carries, use the standard Julia introspection:

julia> ?ReactiveMP.BeforeProductOfTwoMessagesEvent

Event spans

Certain events create a "span". For example all "before" and "after" events can be considered together. To track these relationships ReactiveMP uses the span_id field in such events and uses the ReactiveMP.generate_span_id function to generate shared ids.

ReactiveMP.generate_span_idFunction
generate_span_id(callbacks)

Generates a unique identifier used for "before" and "after" events (see for example BeforeMessageRuleCallEvent and [AfterMessageRuleCallEvent]](@ref)). If callbacks are not set (e.g. callbacks is nothing), returns nothing.

The current implementation uses UUIDs.uuid4 to generate span IDs, but that may change in the future.

source

Custom callbacks can overwrite the ReactiveMP.generate_span_id to return nothing if necessary. Note, however, that ReactiveMP.MergedCallbacks would still use the default implementation.

All defined events

Here is the list of predefined event types, to which a custom callback handler can react to.

ReactiveMP.BeforeMessageRuleCallEventType
BeforeMessageRuleCallEvent{M, Ms, Mr} <: Event{:before_message_rule_call}

This event fires right before computing the message and calling the corresponding rule.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.AfterMessageRuleCallEvent, ReactiveMP.generate_span_id

source
ReactiveMP.AfterMessageRuleCallEventType
AfterMessageRuleCallEvent{M, Ms, Mr, R, A} <: Event{:after_message_rule_call}

This event fires right after computing the message and calling the corresponding rule.

Fields

  • mapping: of type ReactiveMP.MessageMapping, contains information about the node type, etc
  • messages: typically of type Tuple if present, nothing otherwise
  • marginals: typically of type Tuple if present, nothing otherwise
  • result: the result of the rule invocation (or rulefallback), can be any type
  • annotations: the annotations attached to the result, of type ReactiveMP.AnnotationDict
  • span_id: an id shared with the corresponding ReactiveMP.BeforeMessageRuleCallEvent

See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeMessageRuleCallEvent, ReactiveMP.generate_span_id

source
ReactiveMP.BeforeProductOfTwoMessagesEventType
BeforeProductOfTwoMessagesEvent{V, C, L, R} <: Event{:before_product_of_two_messages}

This event fires right before computing the product of two messages.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.AfterProductOfTwoMessagesEvent, ReactiveMP.generate_span_id

source
ReactiveMP.AfterProductOfTwoMessagesEventType
AfterProductOfTwoMessagesEvent{V, C, L, R, Rs, A} <: Event{:after_product_of_two_messages}

This event fires right after computing the product of two messages.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeProductOfTwoMessagesEvent, ReactiveMP.generate_span_id

source
ReactiveMP.BeforeProductOfMessagesEventType
BeforeProductOfMessagesEvent{V, C, Ms} <: Event{:before_product_of_messages}

This event fires right before computing the product of a collection of messages (i.e. at the beginning of ReactiveMP.compute_product_of_messages).

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.AfterProductOfMessagesEvent, ReactiveMP.generate_span_id

source
ReactiveMP.AfterProductOfMessagesEventType
AfterProductOfMessagesEvent{V, C, Ms, R} <: Event{:after_product_of_messages}

This event fires right after computing the product of a collection of messages (i.e. at the end of ReactiveMP.compute_product_of_messages).

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeProductOfMessagesEvent, ReactiveMP.generate_span_id

source
ReactiveMP.BeforeFormConstraintAppliedEventType
BeforeFormConstraintAppliedEvent{V, C, S, D} <: Event{:before_form_constraint_applied}

This event fires right before applying the form constraint via ReactiveMP.constrain_form. Fires in both ReactiveMP.FormConstraintCheckEach and ReactiveMP.FormConstraintCheckLast strategies.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.AfterFormConstraintAppliedEvent, ReactiveMP.generate_span_id

source
ReactiveMP.AfterFormConstraintAppliedEventType
AfterFormConstraintAppliedEvent{V, C, S, D, R} <: Event{:after_form_constraint_applied}

This event fires right after applying the form constraint via ReactiveMP.constrain_form. Fires in both ReactiveMP.FormConstraintCheckEach and ReactiveMP.FormConstraintCheckLast strategies.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeFormConstraintAppliedEvent, ReactiveMP.generate_span_id

source
ReactiveMP.BeforeMarginalComputationEventType
BeforeMarginalComputationEvent{V, C, Ms} <: Event{:before_marginal_computation}

This event fires right before computing the marginal for a ReactiveMP.RandomVariable from its incoming messages.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.AfterMarginalComputationEvent, ReactiveMP.generate_span_id

source
ReactiveMP.AfterMarginalComputationEventType
AfterMarginalComputationEvent{V, C, Ms, R} <: Event{:after_marginal_computation}

This event fires right after computing the marginal for a ReactiveMP.RandomVariable from its incoming messages.

Fields

See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeMarginalComputationEvent, ReactiveMP.generate_span_id

source