/*******************************************************************************
* Copyright 2014 Analog Devices, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
/**
* Classes for controlling the generation and handling of events specific to Dimple.
*
* <h2>Overview</h2>
*
* Dimple events are intended for use in monitoring changes to a Dimple model, data values
* or solver state. The events can either by passed to an external monitoring system, logged
* somewhere, or even used synchronously respond to changes. The event system is is designed to
* have minimal overhead when there are no listeners active for a given event type.
*
* <h2>Events</h2>
*
* Events are represented by instances of concrete subclasses of the class
* {@linkplain com.analog.lyric.dimple.events.DimpleEvent DimpleEvent}. There are three classes of event types,
* represented by distinct abstract subclasses:
* <ul>
* <li>{@linkplain com.analog.lyric.dimple.events.ModelEvent ModelEvent}: changes to model such as add or removal of
* factors or variables.
* <li>{@linkplain com.analog.lyric.dimple.events.DataEvent DataEvent}: changes to observed data values or variable
* input distributions.
* <li>{@linkplain com.analog.lyric.dimple.events.SolverEvent SolverEvent}: solver-specific events such as message
* updates for belief-propagation solvers or new sample values for sampling solvers.
* </ul>
*
* A full hierarchy of events can be seen easily using the Type Hierarchy view in Eclipse (press
* Ctrl+Shift+H, type "DimpleEvent" in the dialog, and hit "Ok").
*
* <h2>Event listeners</h2>
*
* An instance of the {@linkplain com.analog.lyric.dimple.events.DimpleEventListener DimpleEventListener}
* class is responsible for dispatching of events raised from event sources from the same
* {@linkplain com.analog.lyric.dimple.environment.DimpleEnvironment Dimple environment}. Almost always the
* {@linkplain com.analog.lyric.dimple.environment.DimpleEnvironment#active() active} environment is the
* only environment, but if there is more than one, the event source object knows which environment it belongs
* to. If there is no listener on the environment, which is the default, then no events should be generated.
* You may set or clear the listener on the environment using the
* {@linkplain com.analog.lyric.dimple.environment.DimpleEnvironment#setEventListener setEventListener} method or
* you can simply force creation of a listener using the
* {@linkplain com.analog.lyric.dimple.environment.DimpleEnvironment#createEventListener createEventListener} method.
* <p>
* Once a listener has been associated with the environment, then one or more handlers may be registered to
* handle events. The registration must specify the base class of the type of event to
* be handled and the root object on which events will be raised. It will be easiest to register for
* events on the root factor graph, but it may sometimes be desirable to set up handlers for specific variables,
* factors or subgraphs. For instance, to register handlers for various belief propagation messages on
* a graph, you could write:
*
* <pre>
* void registerHandlers(FactorGraph fg)
* {
* DimpleEventListener listener = fg.getEnvironment().createEventListener();
* listener.register(factorMessageHandler, FactorToVariableMessageEvent.class, fg);
* listener.register(variableMessageHandler, VariableToFactorMessageEvent.class, fg);
* }
* </pre>
*
* It is also possible to register for events on the environment itself, which will affect all graphs
* in the environment:
*
* <pre>
* DimpleEnvironment env = DimpleEnvironment.active();
* DimpleEventListener listener = env.createEventListener();
* listener.register(factorMessageHandler, FactorToVariableMessageEvent.class, env);
* listener.register(variableMessageHandler, VariableToFactorMessageEvent.class, env);
* </pre>
* Handlers can be removed by one of the various {@code unregister} methods on the listener.
* <p>
* Changes to event registration or the value of the root listener are not guaranteed to take effect until
* the next time the affected objects have been initialized or
* {@linkplain com.analog.lyric.dimple.events.IDimpleEventSource#notifyListenerChanged() notifyListenerChanged()}
* has been invoked on the object that generates the event. This is important for model events in particular
* since model changes typically occur prior to initialization.
*
* <h2>Event handlers</h2>
*
* Dimple event handlers are objects that implement the
* {@linkplain com.analog.lyric.dimple.events.IDimpleEventHandler IDimpleEventHandler}
* interface. In practice most handlers should simply extend
* {@linkplain com.analog.lyric.dimple.events.DimpleEventHandler DimpleEventHandler}.
* For example, here is a simple handler class that simply prints events out to the console with a verbosity of one:
*
* <pre>
* public class EventPrinter extends DimpleEventHandler<DimpleEvent>
* {
* public void handleEvent(DimpleEvent event)
* {
* event.println(System.out, 1);
* }
* }
* </pre>
*
* Handler classes that are specific to a particular event subclass can be parameterized appropriately
* to avoid the need for downcasts. For example, here is a simple handler that keeps a running total
* of the total graph score during Gibbs sampling based on sample score differences:
*
* <pre>
* public class RunningScoreHandler extends DimpleEventHandler<GibbsScoredVariableUpdateEvent>
* {
* public double score;
*
* RunningScoreHandler(double startingScore)
* {
* score = startingScore;
* }
*
* public void handleEvent(GibbsScoredVariableUpdateEvent event)
* {
* score += event.getScoreDifference();
* }
* }
* </pre>
*
* <h2>Concurrency issues</h2>
*
* Handlers are invoked synchronously as soon as the events have been constructed. Accessing the attributes
* of the event objects is guaranteed to be thread safe, but calling methods on the event source or model
* objects referred to in the event may not be safe.
*
* <h2>Serialization</h2>
*
* Dimple events implement the {@link java.io.Serializable} interface, which allows them to be serialized
* to binary form for persistent storage or transmission to a remote monitor. However, note that events
* purposely will not attempt to serialize references to model or solver elements, since that would require
* serializing the entire graph. This means that deserialized event objects will contain null references for
* any such object. Instead of serializing the actual object, the name and id of the object will be serialized.
* <p>
* @since
* <li>0.07 - support for DimpleEnvironment
* <li>0.06 - package was first introduced
* @author Christopher Barber
*/
@org.eclipse.jdt.annotation.NonNullByDefault
package com.analog.lyric.dimple.events;