/*******************************************************************************
* Copyright 2014-2015 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.environment;
import static org.junit.Assert.*;
import java.security.SecureRandom;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Test;
import com.analog.lyric.dimple.environment.DimpleEnvironment;
import com.analog.lyric.dimple.environment.ExtendedLevel;
import com.analog.lyric.dimple.events.DimpleEvent;
import com.analog.lyric.dimple.events.DimpleEventListener;
import com.analog.lyric.dimple.events.EventPrinter;
import com.analog.lyric.dimple.events.IDimpleEventHandler;
import com.analog.lyric.dimple.events.IDimpleEventSource;
import com.analog.lyric.dimple.events.IModelEventSource;
import com.analog.lyric.dimple.factorfunctions.Normal;
import com.analog.lyric.dimple.model.core.FactorGraph;
import com.analog.lyric.dimple.model.core.Ids;
import com.analog.lyric.dimple.model.variables.Real;
import com.analog.lyric.dimple.options.BPOptions;
import com.analog.lyric.dimple.options.DimpleOptionHolder;
import com.analog.lyric.dimple.schedulers.GibbsRandomScanScheduler;
import com.analog.lyric.dimple.schedulers.validator.AllEdgeScheduleValidator;
import com.analog.lyric.dimple.solvers.core.proposalKernels.NormalProposalKernel;
import com.analog.lyric.dimple.solvers.gibbs.GibbsSolver;
import com.analog.lyric.dimple.solvers.gibbs.samplers.generic.SliceSampler;
import com.analog.lyric.dimple.test.DimpleTestBase;
import com.analog.lyric.math.DimpleRandom;
import com.analog.lyric.util.test.TestLogger;
/**
* Unit tests for {@link DimpleEnvironment} class.
* @since 0.07
* @author Christopher Barber
*/
public class TestDimpleEnvironment extends DimpleTestBase
{
@SuppressWarnings("unused")
@Test
public void testInstances()
{
// Assume JUnit tests will not be run from MATLAB
assertFalse(DimpleEnvironment.loadedFromMATLAB());
assertNull(DimpleEnvironment.withId(new SecureRandom().nextLong()));
final DimpleEnvironment global1 = DimpleEnvironment.defaultEnvironment();
final DimpleEnvironment local1 = DimpleEnvironment.active();
assertSame(global1, local1);
assertSame(global1, DimpleEnvironment.withId(global1.getEnvId()));
UUID uid = global1.getUUID();
assertEquals(2, uid.variant());
assertEquals(Ids.DIMPLE_UUID_VERSION, uid.version());
assertEquals(0, uid.getLeastSignificantBits() & (1L<<62) - 1);
Thread thread1 = new Thread() {
@Override
public void run()
{
assertSame(global1, DimpleEnvironment.active());
DimpleEnvironment local2 = new DimpleEnvironment();
assertNotEquals(local2.getEnvId(), global1.getEnvId());
assertSame(local2, DimpleEnvironment.withId(local2.getEnvId()));
DimpleEnvironment.setActive(local2);
assertSame(local2, DimpleEnvironment.active());
}
};
thread1.start();
try
{
thread1.join();
}
catch (InterruptedException ex)
{
fail(ex.toString());
}
assertSame(local1, DimpleEnvironment.active());
final DimpleEnvironment global2 = new DimpleEnvironment();
DimpleEnvironment.setDefaultEnvironment(global2);
assertSame(global2, DimpleEnvironment.defaultEnvironment());
assertSame(local1, DimpleEnvironment.active());
assertNotEquals(uid, global2.getUUID());
assertSame(local1.random(), DimpleEnvironment.activeRandom());
DimpleRandom prevRandom = local1.random();
DimpleRandom newRandom = new DimpleRandom();
assertSame(prevRandom, local1.setRandom(newRandom));
assertSame(newRandom, local1.random());
Thread thread2 = new Thread() {
@Override
public void run()
{
assertSame(global2, DimpleEnvironment.active());
DimpleEnvironment.setDefaultEnvironment(global1);
assertSame(global1, DimpleEnvironment.defaultEnvironment());
assertSame(global2, DimpleEnvironment.active());
assertSame(global2.random(), DimpleEnvironment.activeRandom());
}
};
thread2.start();
try
{
thread2.join();
}
catch (InterruptedException ex)
{
fail(ex.toString());
}
try
{
new DimpleEnvironment(Ids.ENV_ID_MAX + 1);
}
catch (IllegalArgumentException ex)
{
}
catch (Throwable ex)
{
fail("expected IllegalArgumentException");
}
try
{
new DimpleEnvironment(Ids.ENV_ID_MIN - 1);
}
catch (IllegalArgumentException ex)
{
}
catch (Throwable ex)
{
fail("expected IllegalArgumentException");
}
try
{
new DimpleEnvironment(DimpleEnvironment.active().getEnvId());
}
catch (IllegalStateException ex)
{
}
catch (Throwable ex)
{
fail("expected IllegalStateException");
}
}
@Test
public void testEventSourceMethods()
{
DimpleEnvironment global = DimpleEnvironment.defaultEnvironment();
assertNull(global.getContainingGraph());
assertNull(global.getEventParent());
assertNull(global.getModelEventSource());
global.notifyListenerChanged(); // does nothing
assertEquals("DimpleEnvironment", global.getEventSourceName());
class TestSource extends DimpleOptionHolder
{
int notifyCount = 0;
@Override
public @Nullable FactorGraph getContainingGraph()
{
return null;
}
@Override
public @Nullable IDimpleEventSource getEventParent()
{
return null;
}
@Override
public String getEventSourceName()
{
return "test";
}
@Override
public @Nullable IModelEventSource getModelEventSource()
{
return null;
}
@Override
public void notifyListenerChanged()
{
++notifyCount;
}
}
TestSource source1 = new TestSource();
TestSource source2 = new TestSource();
IDimpleEventHandler<DimpleEvent> handler = new EventPrinter();
assertNull(global.getEventListener());
DimpleEventListener listener = global.createEventListener();
assertNotNull(listener);
assertSame(listener, global.createEventListener());
assertSame(listener, global.getEventListener());
listener.register(handler, DimpleEvent.class, source1);
global.setEventListener(null);
global.setEventListener(null);
assertNull(global.getEventListener());
assertEquals(1, source1.notifyCount);
global.setEventListener(listener);
global.setEventListener(listener);
assertSame(listener, global.getEventListener());
assertEquals(2, source1.notifyCount);
DimpleEventListener listener2 = new DimpleEventListener();
listener2.register(handler, DimpleEvent.class, source2);
global.setEventListener(listener2);
global.setEventListener(listener2);
assertSame(listener2, global.getEventListener());
assertEquals(3, source1.notifyCount);
assertEquals(1, source2.notifyCount);
}
@Test
public void testLogging()
{
assertFalse(DimpleEnvironment.loadedFromMATLAB());
DimpleEnvironment env = DimpleEnvironment.active();
Logger defaultLogger = env.logger();
assertSame(defaultLogger, Logger.getLogger("com.analog.lyric.dimple"));
assertSame(defaultLogger, DimpleEnvironment.getDefaultLogger());
TestLogger testLogger = new TestLogger("com.analog.lyric.dimple");
env.setLogger(testLogger);
assertSame(testLogger, env.logger());
DimpleEnvironment.logWarning("'%s'","hi there");
LogRecord record = testLogger.loggedRecords().remove();
assertEquals(Level.WARNING, record.getLevel());
assertEquals("'hi there'", record.getMessage());
assertTrue(testLogger.loggedRecords().isEmpty());
DimpleEnvironment.logError("'%s'","whoops");
record = testLogger.loggedRecords().remove();
assertEquals(ExtendedLevel.ERROR, record.getLevel());
assertEquals("'whoops'", record.getMessage());
assertTrue(testLogger.loggedRecords().isEmpty());
DimpleEnvironment.log(Level.INFO, "info");
record = testLogger.loggedRecords().remove();
assertEquals(Level.INFO, record.getLevel());
assertEquals("info", record.getMessage());
assertTrue(testLogger.loggedRecords().isEmpty());
}
@Test
public void testRegistries()
{
DimpleEnvironment env = DimpleEnvironment.active();
assertEquals(Normal.class, env.factorFunctions().getClass("Normal"));
assertSame(env.factorFunctions(), env.factorFunctions());
assertNull(env.factorGraphs().getGraphWithId(0));
assertSame(env.factorGraphs(), env.factorGraphs());
FactorGraph fg1 = new FactorGraph();
FactorGraph fg2 = new FactorGraph();
Real v1 = new Real();
fg1.addVariables(v1);
assertSame(fg1, env.factorGraphs().getGraphWithId(fg1.getGraphId()));
assertSame(fg2, env.factorGraphs().getGraphWithId(fg2.getGraphId()));
assertSame(v1, env.getNodeByGlobalId(v1.getGlobalId()));
assertNull(env.getNodeByGlobalId(0));
assertEquals(SliceSampler.class, env.genericSamplers().getClass("SliceSampler"));
assertSame(env.genericSamplers(), env.genericSamplers());
assertEquals(BPOptions.iterations, env.optionRegistry().get("BPOptions.iterations"));
assertSame(env.optionRegistry(), env.optionRegistry());
assertEquals(NormalProposalKernel.class, env.proposalKernels().getClass("NormalProposalKernel"));
assertSame(env.proposalKernels(), env.proposalKernels());
assertEquals(GibbsSolver.class, env.solvers().getClass("Gibbs"));
assertSame(env.solvers(), env.solvers());
assertEquals(GibbsRandomScanScheduler.class, env.schedulers().getClass("GibbsRandomScanScheduler"));
assertSame(env.schedulers(), env.schedulers());
assertEquals(AllEdgeScheduleValidator.class, env.scheduleValidators().getClass("AllEdgeScheduleValidator"));
}
}