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
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.
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
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
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
1If the NamedTuple does not have a field corresponding to the event name, the event will be ignored.
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.
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.
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.
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: helloSee also: ReactiveMP.invoke_callback, ReactiveMP.handle_event
ReactiveMP.MergedCallbacks — Type
MergedCallbacks{C}(callbacks)The result of the ReactiveMP.merge_callbacks procedure.
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:
| Symbol | Struct |
|---|---|
:before_message_rule_call | ReactiveMP.BeforeMessageRuleCallEvent |
:after_product_of_two_messages | ReactiveMP.AfterProductOfTwoMessagesEvent |
:before_form_constraint_applied | ReactiveMP.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_messagesTo see which fields an event carries, use the standard Julia introspection:
julia> ?ReactiveMP.BeforeProductOfTwoMessagesEventEvent 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.
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
mapping: of typeReactiveMP.MessageMapping, contains information about the node type, etcmessages: typically of typeTupleif present,nothingotherwisemarginals: typically of typeTupleif present,nothingotherwisespan_id: an id shared with the correspondingReactiveMP.AfterMessageRuleCallEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.AfterMessageRuleCallEvent, ReactiveMP.generate_span_id
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 typeReactiveMP.MessageMapping, contains information about the node type, etcmessages: typically of typeTupleif present,nothingotherwisemarginals: typically of typeTupleif present,nothingotherwiseresult: the result of the rule invocation (orrulefallback), can be any typeannotations: the annotations attached to the result, of typeReactiveMP.AnnotationDictspan_id: an id shared with the correspondingReactiveMP.BeforeMessageRuleCallEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeMessageRuleCallEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.AbstractVariablecontext: of typeReactiveMP.MessageProductContextleft: of typeReactiveMP.Message, the left-hand side message in the productright: of typeReactiveMP.Message, the right-hand side message in the productspan_id: an id shared with the correspondingReactiveMP.AfterProductOfTwoMessagesEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.AfterProductOfTwoMessagesEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.AbstractVariablecontext: of typeReactiveMP.MessageProductContextleft: of typeReactiveMP.Message, the left-hand side message in the productright: of typeReactiveMP.Message, the right-hand side message in the productresult: of typeReactiveMP.Message, the resulting message from the productannotations: the annotations attached to the result, of typeReactiveMP.AnnotationDictspan_id: an id shared with the correspondingReactiveMP.BeforeProductOfTwoMessagesEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeProductOfTwoMessagesEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.AbstractVariablecontext: of typeReactiveMP.MessageProductContextmessages: the collection of messages to be multipliedspan_id: an id shared with the correspondingReactiveMP.AfterProductOfMessagesEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.AfterProductOfMessagesEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.AbstractVariablecontext: of typeReactiveMP.MessageProductContextmessages: the original collection of messages that were multipliedresult: of typeReactiveMP.Message, the final result after folding and form constraint applicationspan_id: an id shared with the correspondingReactiveMP.BeforeProductOfMessagesEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeProductOfMessagesEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.AbstractVariablecontext: of typeReactiveMP.MessageProductContextstrategy: the form constraint check strategy being used (e.g.ReactiveMP.FormConstraintCheckEachorReactiveMP.FormConstraintCheckLast)distribution: the distribution about to be constrainedspan_id: an id shared with the correspondingReactiveMP.AfterFormConstraintAppliedEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.AfterFormConstraintAppliedEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.AbstractVariablecontext: of typeReactiveMP.MessageProductContextstrategy: the form constraint check strategy being used (e.g.ReactiveMP.FormConstraintCheckEachorReactiveMP.FormConstraintCheckLast)distribution: the distribution before the constraint was appliedresult: the distribution after the constraint was appliedspan_id: an id shared with the correspondingReactiveMP.BeforeFormConstraintAppliedEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeFormConstraintAppliedEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.RandomVariablecontext: of typeReactiveMP.MessageProductContextmessages: the collection of incoming messages used to compute the marginalspan_id: an id shared with the correspondingReactiveMP.AfterMarginalComputationEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.AfterMarginalComputationEvent, ReactiveMP.generate_span_id
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
variable: of typeReactiveMP.RandomVariablecontext: of typeReactiveMP.MessageProductContextmessages: the collection of incoming messages used to compute the marginalresult: the computed marginalspan_id: an id shared with the correspondingReactiveMP.BeforeMarginalComputationEvent
See also: ReactiveMP.invoke_callback, ReactiveMP.BeforeMarginalComputationEvent, ReactiveMP.generate_span_id