package org.djutils.stats.summarizers.event; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.djutils.event.Event; import org.djutils.event.EventInterface; import org.djutils.event.EventListenerInterface; import org.djutils.event.EventType; import org.djutils.metadata.MetaData; import org.djutils.metadata.ObjectDescriptor; import org.junit.Test; /** * The EventBasedWeightedTallyTest tests the EventBasedWeightedTally. *

* Copyright (c) 2002-2021 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See * for project information https://simulation.tudelft.nl. The DSOL * project is distributed under a three-clause BSD-style license, which can be found at * * https://simulation.tudelft.nl/dsol/3.0/license.html.
* @author Peter Jacobs * @since 1.5 */ public class EventBasedWeightedTallyTest { /** an event to fire. */ private static final EventType VALUE_EVENT = new EventType("VALUE_EVENT", new MetaData("WeightAndValue", "Double[] with Double weight and Double value ", new ObjectDescriptor[] { new ObjectDescriptor("Weight", "Double weight", Double.class), new ObjectDescriptor("Valuie", "Double value", Double.class) })); /** Test the EventBasedWeightedTally. */ @Test public void testEventBasedWeightedTally() { String description = "THIS EVENT BASED WEIGHTED TALLY IS TESTED"; EventBasedWeightedTally wt = new EventBasedWeightedTally(description); // check the description assertEquals(description, wt.getDescription()); assertTrue(wt.toString().contains(description)); // now we check the initial values assertTrue(Double.isNaN(wt.getMin())); assertTrue(Double.isNaN(wt.getMax())); assertTrue(Double.isNaN(wt.getWeightedSampleMean())); assertTrue(Double.isNaN(wt.getWeightedSampleVariance())); assertTrue(Double.isNaN(wt.getWeightedSampleStDev())); assertEquals(0.0, wt.getWeightedSum(), 0.0); assertEquals(0L, wt.getN()); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.1 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.2 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.3 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.4 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.5 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.6 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.7 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.8 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.9 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 2.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 1.0 })); // Now we check the EventBasedWeightedTally assertEquals(2.0, wt.getMax(), 1.0E-6); assertEquals(1.0, wt.getMin(), 1.0E-6); assertEquals(11, wt.getN()); assertEquals(1.5 * 0.1 * 11, wt.getWeightedSum(), 1.0E-6); assertEquals(1.5, wt.getWeightedSampleMean(), 1.0E-6); assertEquals(0.316228, wt.getWeightedPopulationStDev(), 1.0E-6); // Computed with Excel sheet assertEquals(0.100000, wt.getWeightedPopulationVariance(), 1.0E-6); assertEquals(0.331662, wt.getWeightedSampleStDev(), 1.0E-6); // Computed with Excel sheet assertEquals(0.110000, wt.getWeightedSampleVariance(), 1.0E-6); // Let's compute the standard deviation double variance = 0; for (int i = 0; i < 11; i++) { variance += Math.pow(1.5 - (1.0 + i / 10.0), 2); } variance = variance / 10.0; double stDev = Math.sqrt(variance); assertEquals(variance, wt.getWeightedSampleVariance(), 1.0E-6); assertEquals(stDev, wt.getWeightedSampleStDev(), 1.0E-6); try { wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { -0.1, 123.456 })); fail("negative weight should have thrown an exception"); } catch (IllegalArgumentException iae) { // Ignore expected exception } try { wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", "123")); fail("non Object[] content should have thrown an exception"); } catch (IndexOutOfBoundsException iobe) { // Ignore expected exception } try { wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1 })); fail("Object[] with one argument should have thrown an exception"); } catch (IndexOutOfBoundsException iae) { // Ignore expected exception } try { wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.1, 0.2, 0.3 })); fail("Object[] with thre arguments should have thrown an exception"); } catch (IndexOutOfBoundsException iae) { // Ignore expected exception } try { wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { "bla", 0.2 })); fail("EventBasedWeightedTally should fail on weight !instanceOf Double"); } catch (Exception exception) { assertNotNull(exception); } try { wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.3, "bla" })); fail("EventBasedWeightedTally should fail on value !instanceOf Double"); } catch (Exception exception) { assertNotNull(exception); } } /** Test the EventBasedWeightedTally on a simple example. */ @Test public void testEventBasedWeightedTallySimple() { // From: https://sciencing.com/calculate-time-decimals-5962681.html EventBasedWeightedTally wt = new EventBasedWeightedTally("simple EventBasedWeightedTally statistic"); wt.initialize(); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 13.0, 86.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 23.0, 26.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 4.0, 0.0 })); assertEquals(1716.0, wt.getWeightedSum(), 0.001); assertEquals(42.9, wt.getWeightedSampleMean(), 0.001); // When we shift the times, we should get the same answers wt = new EventBasedWeightedTally("simple EventBasedWeightedTally statistic"); wt.initialize(); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 13.0, 86.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 23.0, 26.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 14.0, 0.0 })); assertEquals(1716.0, wt.getWeightedSum(), 0.001); assertEquals(34.32, wt.getWeightedSampleMean(), 0.001); // When we have observations with duration 0, we should get the same answers wt = new EventBasedWeightedTally("simple EventBasedWeightedTally statistic"); wt.initialize(); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 13.0, 86.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.0, 86.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 23.0, 26.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 4.0, 0.0 })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0.0, 0.0 })); assertEquals(1716.0, wt.getWeightedSum(), 0.001); assertEquals(42.9, wt.getWeightedSampleMean(), 0.001); // Example from NIST: https://www.itl.nist.gov/div898/software/dataplot/refman2/ch2/weightsd.pdf wt = new EventBasedWeightedTally("NIST"); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 1d, 2d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 1d, 3d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0d, 5d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0d, 7d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 4d, 11d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 1d, 13d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 2d, 17d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 1d, 19d })); wt.notify(new Event(VALUE_EVENT, "EventBasedWeightedTallyTest", new Object[] { 0d, 23d })); assertEquals((2 + 3 + 4 * 11 + 13 + 2 * 17 + 19) / 10.0, wt.getWeightedSampleMean(), 0.001); assertEquals(5.82, wt.getWeightedSampleStDev(), 0.01); } /** * Test produced events by EventBasedWeightedTally. */ @Test public void testWeightedTallyEventProduction() { EventBasedWeightedTally weightedTally = new EventBasedWeightedTally("testTally"); assertEquals(weightedTally, weightedTally.getSourceId()); WeightedObservationEventListener woel = new WeightedObservationEventListener(); weightedTally.addListener(woel, StatisticsEvents.WEIGHTED_OBSERVATION_ADDED_EVENT); assertEquals(0, woel.getObservationEvents()); EventType[] types = new EventType[] { StatisticsEvents.N_EVENT, StatisticsEvents.MIN_EVENT, StatisticsEvents.MAX_EVENT, StatisticsEvents.WEIGHTED_POPULATION_MEAN_EVENT, StatisticsEvents.WEIGHTED_POPULATION_VARIANCE_EVENT, StatisticsEvents.WEIGHTED_POPULATION_STDEV_EVENT, StatisticsEvents.WEIGHTED_SUM_EVENT, StatisticsEvents.WEIGHTED_SAMPLE_MEAN_EVENT, StatisticsEvents.WEIGHTED_SAMPLE_VARIANCE_EVENT, StatisticsEvents.WEIGHTED_SAMPLE_STDEV_EVENT }; LoggingEventListener[] listeners = new LoggingEventListener[types.length]; for (int i = 0; i < types.length; i++) { listeners[i] = new LoggingEventListener(); weightedTally.addListener(listeners[i], types[i]); } for (int i = 1; i <= 10; i++) { weightedTally.ingest(1.0 * i, 10.0 * i); } assertEquals(10, woel.getObservationEvents()); // values based on formulas from https://www.itl.nist.gov/div898/software/dataplot/refman2/ch2/weightsd.pdf Object[] expectedValues = new Object[] { 10L, 10.0, 100.0, 70.0, 600.0, 24.4949, 3850.0, 70.0, 666.6667, 25.81989 }; for (int i = 0; i < types.length; i++) { assertEquals("Number of events for listener " + types[i], 10, listeners[i].getNumberOfEvents()); assertEquals("Event sourceId for listener " + types[i], weightedTally, listeners[i].getLastEvent().getSourceId()); assertEquals("Event type for listener " + types[i], types[i], listeners[i].getLastEvent().getType()); if (expectedValues[i] instanceof Long) { assertEquals("Final value for listener " + types[i], expectedValues[i], listeners[i].getLastEvent().getContent()); } else { double e = ((Double) expectedValues[i]).doubleValue(); double c = ((Double) listeners[i].getLastEvent().getContent()).doubleValue(); assertEquals("Final value for listener " + types[i], e, c, 0.001); } } } /** The listener that counts the OBSERVATION_ADDED_EVENT events and checks correctness. */ class WeightedObservationEventListener implements EventListenerInterface { /** */ private static final long serialVersionUID = 1L; /** counter for the event. */ private int observationEvents = 0; @Override public void notify(final EventInterface event) { assertTrue(event.getType().equals(StatisticsEvents.WEIGHTED_OBSERVATION_ADDED_EVENT)); assertTrue("Content of the event has a wrong type, not Object[]: " + event.getContent().getClass(), event.getContent() instanceof Object[]); Object[] c = (Object[]) event.getContent(); assertTrue("Content[0] of the event has a wrong type, not double: " + c[0].getClass(), c[0] instanceof Double); assertTrue("Content[1] of the event has a wrong type, not double: " + c[1].getClass(), c[1] instanceof Double); assertTrue("SourceId of the event has a wrong type, not EventBasedWeightedTally: " + event.getSourceId().getClass(), event.getSourceId() instanceof EventBasedWeightedTally); this.observationEvents++; } /** * @return countEvents */ public int getObservationEvents() { return this.observationEvents; } } }