/******************************************************************************* * 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. ********************************************************************************/ package com.analog.lyric.dimple.test.model.variables; import static org.junit.Assert.*; import java.util.ArrayDeque; import java.util.Queue; import org.eclipse.jdt.annotation.Nullable; import org.junit.Test; import com.analog.lyric.dimple.data.IDatum; import com.analog.lyric.dimple.environment.DimpleEnvironment; import com.analog.lyric.dimple.events.DimpleEventHandler; import com.analog.lyric.dimple.events.DimpleEventListener; import com.analog.lyric.dimple.factorfunctions.Normal; import com.analog.lyric.dimple.model.core.FactorGraph; import com.analog.lyric.dimple.model.domains.DiscreteDomain; import com.analog.lyric.dimple.model.values.Value; import com.analog.lyric.dimple.model.variables.Discrete; import com.analog.lyric.dimple.model.variables.Real; import com.analog.lyric.dimple.model.variables.Variable; import com.analog.lyric.dimple.model.variables.VariableChangeEvent; import com.analog.lyric.dimple.model.variables.VariableFixedValueChangeEvent; import com.analog.lyric.dimple.model.variables.VariableInputChangeEvent; import com.analog.lyric.dimple.model.variables.VariablePriorChangeEvent; import com.analog.lyric.dimple.solvers.core.parameterizedMessages.DiscreteMessage; import com.analog.lyric.dimple.solvers.core.parameterizedMessages.DiscreteWeightMessage; import com.analog.lyric.dimple.test.DimpleTestBase; /** * Test for {@link VariableChangeEvent}s on {@link Variable}. * * @since 0.06 * @author Christopher Barber */ @SuppressWarnings("deprecation") public class TestVariableChangeEvent extends DimpleTestBase { @Test public void test() { // // Set up model // FactorGraph fg = new FactorGraph(); Real r = new Real(); r.setName("r"); fg.addVariables(r); Discrete d = new Discrete(DiscreteDomain.bit()); d.setName("d"); fg.addVariables(d); // // Set up listener // PriorChangeHandler priorHandler = new PriorChangeHandler(); FixedValueChangeHandler fixedHandler = new FixedValueChangeHandler(); InputChangeHandler inputHandler = new InputChangeHandler(); DimpleEventListener listener = DimpleEnvironment.active().createEventListener(); listener.register(priorHandler, VariablePriorChangeEvent.class, false, fg); listener.register(fixedHandler, VariableFixedValueChangeEvent.class, false, fg); listener.register(inputHandler, VariableInputChangeEvent.class, false, fg); fg.initialize(); assertTrue(listener.isListeningFor(VariablePriorChangeEvent.class, r)); assertTrue(listener.isListeningFor(VariableFixedValueChangeEvent.class, r)); final Value r2_3 = Value.createReal(2.3); final Value r4 = Value.createReal(4.0); r.setPrior(r2_3); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.ADDED, null, r2_3); fixedHandler.assertEvent(r, VariableFixedValueChangeEvent.Type.ADDED, null, 2.3); r.setPrior(r4); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.CHANGED, r2_3, r4); fixedHandler.assertEvent(r, VariableFixedValueChangeEvent.Type.CHANGED, 2.3, 4.0); r.setPrior(null); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.REMOVED, r4, null); fixedHandler.assertEvent(r, VariableFixedValueChangeEvent.Type.REMOVED, 4.0, null); priorHandler.assertNoEvent(); fixedHandler.assertNoEvent(); inputHandler.assertNoEvent(); DiscreteMessage d37 = new DiscreteWeightMessage(new double[] { .3, .7 }); DiscreteMessage d46 = new DiscreteWeightMessage(new double[] { .4, .6 }); d.setPrior(d37); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.ADDED, null, d37); fixedHandler.assertNoEvent(); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.ADDED, null, d37.representation()); d.setPrior(d46); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.CHANGED, d37, d46); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.CHANGED, d37.representation(), d46.representation()); d.setPrior(null); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.REMOVED, d46, null); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.REMOVED, d46.representation(), null); d.setPrior(d37); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.ADDED, null, d37); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.ADDED, null, d37.representation()); final Value d0 = Value.createWithIndex(d.getDomain(), 0); d.setPrior(d0); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.CHANGED, d37, d0); fixedHandler.assertEvent(d, VariableFixedValueChangeEvent.Type.ADDED, null, 0); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.REMOVED, d37.representation(), null); d.setPrior(d37); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.CHANGED, d0, d37); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.ADDED, null, d37.representation()); fixedHandler.assertEvent(d, VariableFixedValueChangeEvent.Type.REMOVED, 0, null); Normal normal = new Normal(1.0, 1.0); r.setPrior(normal); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.ADDED, null, normal); inputHandler.assertEvent(r, VariableInputChangeEvent.Type.ADDED, null, normal); fixedHandler.assertNoEvent(); final Value r3 = Value.createReal(3.0); r.setPrior(r3); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.CHANGED, normal, r3); inputHandler.assertEvent(r, VariableInputChangeEvent.Type.REMOVED, normal, null); fixedHandler.assertEvent(r, VariableFixedValueChangeEvent.Type.ADDED, null, 3.0); r.setInput(normal); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.CHANGED, r3, normal); inputHandler.assertEvent(r, VariableInputChangeEvent.Type.ADDED, null, normal); fixedHandler.assertEvent(r, VariableFixedValueChangeEvent.Type.REMOVED, 3.0, null); priorHandler.assertNoEvent(); inputHandler.assertNoEvent(); fixedHandler.assertNoEvent(); listener.block(VariablePriorChangeEvent.class, false, r); listener.block(VariableFixedValueChangeEvent.class, false, r); r.notifyListenerChanged(); assertFalse(listener.isListeningFor(VariablePriorChangeEvent.class, r)); assertFalse(listener.isListeningFor(VariableFixedValueChangeEvent.class, r)); final Value r1 = Value.createReal(1.0); r.setPrior(r1); priorHandler.assertNoEvent(); fixedHandler.assertNoEvent(); inputHandler.assertEvent(r, VariableInputChangeEvent.Type.REMOVED, normal, null); listener.block(VariableInputChangeEvent.class, false, r); r.notifyListenerChanged(); d.notifyListenerChanged(); assertTrue(listener.isListeningFor(VariablePriorChangeEvent.class, d)); assertTrue(listener.isListeningFor(VariableFixedValueChangeEvent.class, d)); assertTrue(listener.isListeningFor(VariableInputChangeEvent.class, d)); final Value d1 = Value.create(d.getDomain(), 1.0); d.setPrior(d1); priorHandler.assertEvent(d, VariablePriorChangeEvent.Type.CHANGED, d37, d1); fixedHandler.assertEvent(d, VariableFixedValueChangeEvent.Type.ADDED, null, 1); inputHandler.assertEvent(d, VariableInputChangeEvent.Type.REMOVED, d37.representation(), null); listener.unblock(VariablePriorChangeEvent.class, r); listener.unblock(VariableFixedValueChangeEvent.class, r); r.notifyListenerChanged(); r.setPrior(normal); priorHandler.assertEvent(r, VariablePriorChangeEvent.Type.CHANGED, r1, normal); inputHandler.assertNoEvent(); fixedHandler.assertEvent(r, VariableFixedValueChangeEvent.Type.REMOVED, 1.0, null); DimpleEnvironment.active().setEventListener(null); r.setPrior(r2_3); priorHandler.assertNoEvent(); inputHandler.assertNoEvent(); fixedHandler.assertNoEvent(); } private static class PriorChangeHandler extends DimpleEventHandler<VariablePriorChangeEvent> { private Queue<VariablePriorChangeEvent> _events = new ArrayDeque<VariablePriorChangeEvent>(); @Override public void handleEvent(VariablePriorChangeEvent event) { Variable var = event.getModelObject(); assertEquals(var.getPrior(), event.getNewPrior()); switch (event.getType()) { case ADDED: assertNotNull(var.getPrior()); assertNull(event.getOldPrior()); break; case REMOVED: assertNull(var.getPrior()); assertNotNull(event.getOldPrior()); break; case CHANGED: assertNotNull(event.getNewPrior()); assertNotNull(event.getOldPrior()); assertNotEquals(event.getNewPrior(), event.getOldPrior()); } _events.add(event); } void assertEvent(Variable var, VariablePriorChangeEvent.Type type, @Nullable IDatum oldValue, @Nullable IDatum newValue) { VariablePriorChangeEvent event = _events.poll(); assertNotNull(event); assertSame(var, event.getModelObject()); assertEquals(type, event.getType()); assertEquals(oldValue, event.getOldPrior()); assertEquals(newValue, event.getNewPrior()); } void assertNoEvent() { assertTrue(_events.isEmpty()); } } private static class FixedValueChangeHandler extends DimpleEventHandler<VariableFixedValueChangeEvent> { private Queue<VariableFixedValueChangeEvent> _events = new ArrayDeque<VariableFixedValueChangeEvent>(); @Override public void handleEvent(VariableFixedValueChangeEvent event) { Variable var = event.getModelObject(); assertEquals(var.getFixedValueObject(), event.getNewValue()); switch (event.getType()) { case ADDED: assertTrue(var.hasFixedValue()); assertNull(event.getOldValue()); break; case REMOVED: assertFalse(var.hasFixedValue()); assertNull(event.getNewValue()); assertNotNull(event.getOldValue()); break; case CHANGED: assertTrue(var.hasFixedValue()); assertNotNull(event.getNewValue()); assertNotNull(event.getOldValue()); } _events.add(event); } void assertEvent(Variable var, VariableFixedValueChangeEvent.Type type, @Nullable Object oldValue, @Nullable Object newValue) { VariableFixedValueChangeEvent event = _events.poll(); assertNotNull(event); assertSame(var, event.getModelObject()); assertEquals(type, event.getType()); assertEquals(oldValue, event.getOldValue()); assertEquals(newValue, event.getNewValue()); } void assertNoEvent() { assertTrue(_events.isEmpty()); } } private static class InputChangeHandler extends DimpleEventHandler<VariableInputChangeEvent> { private Queue<VariableInputChangeEvent> _events = new ArrayDeque<VariableInputChangeEvent>(); @Override public void handleEvent(VariableInputChangeEvent event) { Variable var = event.getModelObject(); if (event.getNewInput() != null) { assertInputsEqual(var.getInputObject(), event.getNewInput()); } switch (event.getType()) { case ADDED: assertTrue(!var.hasFixedValue()); assertNull(event.getOldInput()); break; case REMOVED: assertNull(event.getNewInput()); assertNotNull(event.getOldInput()); break; case CHANGED: assertNotNull(event.getNewInput()); assertNotNull(event.getOldInput()); } _events.add(event); } void assertEvent(Variable var, VariableInputChangeEvent.Type type, @Nullable Object oldInput, @Nullable Object newInput) { VariableInputChangeEvent event = _events.poll(); assertNotNull(event); assertSame(var, event.getModelObject()); assertEquals(type, event.getType()); assertInputsEqual(oldInput, event.getOldInput()); assertInputsEqual(newInput, event.getNewInput()); } void assertNoEvent() { assertTrue(_events.isEmpty()); } } static void assertInputsEqual(@Nullable Object input1, @Nullable Object input2) { if (input1 instanceof double[]) { assertArrayEquals((double[])input1, (double[])input2, 1e-15); } else { assertEquals(input1, input2); } } }