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.Event — Type
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_name — Function
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_event — Function
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_callback — Function
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_callbacks — Function
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_id — Function
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.BeforeMessageRuleCallEvent — Type
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.AfterMessageRuleCallEvent — Type
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.BeforeProductOfTwoMessagesEvent — Type
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.AfterProductOfTwoMessagesEvent — Type
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.BeforeProductOfMessagesEvent — Type
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.AfterProductOfMessagesEvent — Type
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.BeforeFormConstraintAppliedEvent — Type
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.AfterFormConstraintAppliedEvent — Type
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.BeforeMarginalComputationEvent — Type
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.AfterMarginalComputationEvent — Type
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