1 package org.opentrafficsim.core.distributions;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertNotEquals;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.lang.reflect.Field;
10 import java.util.ArrayList;
11 import java.util.List;
12
13 import org.junit.Test;
14 import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
15
16 import nl.tudelft.simulation.jstats.streams.MersenneTwister;
17 import nl.tudelft.simulation.jstats.streams.StreamInterface;
18
19
20
21
22
23
24
25
26
27
28 public class DistributionTest
29 {
30
31
32
33
34 @Test
35 public final void distributionTest() throws ProbabilityException
36 {
37 StreamInterface si = new MersenneTwister(1234);
38 try
39 {
40 new Distribution<TestObject>(null, si);
41 fail("Null pointer for generators should have thrown a ProbabilityException");
42 }
43 catch (ProbabilityException npe)
44 {
45
46 }
47
48 List<Distribution.FrequencyAndObject<TestObject>> generators =
49 new ArrayList<Distribution.FrequencyAndObject<TestObject>>();
50 try
51 {
52 new Distribution<TestObject>(generators, null);
53 fail("Null pointer for stream interface should have thrown a ProbabilityException");
54 }
55 catch (ProbabilityException npe)
56 {
57
58 }
59
60 Distribution<TestObject> dist = new Distribution<TestObject>(generators, si);
61 assertEquals("size should be 0", 0, dist.size());
62 try
63 {
64 dist.draw();
65 fail("draw with empty set should have thrown a ProbabilityException");
66 }
67 catch (ProbabilityException pe)
68 {
69
70 }
71
72 TestObject to = new TestObject();
73 Distribution.FrequencyAndObject<TestObject> generator =
74 new Distribution.FrequencyAndObject<DistributionTest.TestObject>(123, to);
75 try
76 {
77 dist.add(1, generator);
78 fail("should have thrown an IndexOutOfBoundsException");
79 }
80 catch (IndexOutOfBoundsException e)
81 {
82
83 }
84
85 try
86 {
87 dist.add(-1, generator);
88 fail("should have thrown an IndexOutOfBoundsException");
89 }
90 catch (IndexOutOfBoundsException e)
91 {
92
93 }
94
95 dist.add(0, generator);
96 assertEquals("size should now be 1", 1, dist.size());
97 dist.remove(0);
98 assertEquals("size should be 0", 0, dist.size());
99 dist.add(generator);
100 assertEquals("size should now be 1", 1, dist.size());
101 try
102 {
103 dist.remove(1);
104 fail("Bad index for remove should have thrown an IndexOutOfBoundsException");
105 }
106 catch (IndexOutOfBoundsException e)
107 {
108
109 }
110
111 try
112 {
113 dist.remove(-1);
114 fail("Bad index for remove should have thrown an IndexOutOfBoundsException");
115 }
116 catch (IndexOutOfBoundsException e)
117 {
118
119 }
120
121 for (int i = 0; i < 1000; i++)
122 {
123 TestObject to2 = dist.draw();
124 assertEquals("Result of draw() should be equal to to", to, to2);
125 }
126 try
127 {
128 dist.modifyFrequency(1, 1);
129 fail("Bad index for modify should have thrown an IndexOutOfBoundsException");
130 }
131 catch (ProbabilityException e)
132 {
133
134 }
135
136 try
137 {
138 dist.modifyFrequency(-1, 1);
139 fail("Bad index for modify should have thrown an IndexOutOfBoundsException");
140 }
141 catch (ProbabilityException e)
142 {
143
144 }
145
146 try
147 {
148 dist.modifyFrequency(0, -1);
149 fail("Bad frequency for modify should have thrown a ProbabilityException");
150 }
151 catch (ProbabilityException pe)
152 {
153
154 }
155
156 dist.modifyFrequency(0, 0);
157 try
158 {
159 dist.draw();
160 fail("Sum of frequencies == 0 should have thrown a ProbabilityException");
161 }
162 catch (ProbabilityException pe)
163 {
164
165 }
166
167 TestObject to2 = new TestObject();
168 dist.add(new Distribution.FrequencyAndObject<TestObject>(10, to2));
169 assertEquals("element 0 should be to", to, dist.get(0).getObject());
170 assertEquals("element 1 should be to2", to2, dist.get(1).getObject());
171 assertEquals("frequency of element 0 should be 0", 0, dist.get(0).getFrequency(), 0.00001);
172 assertEquals("frequency of element 1 should be 10", 10, dist.get(1).getFrequency(), 0.00001);
173 for (int i = 0; i < 1000; i++)
174 {
175 TestObject to3 = dist.draw();
176 assertEquals("Result of draw() should be equal to to2", to2, to3);
177 }
178 try
179 {
180 dist.get(-1);
181 fail("Negative index should have thrown in a ProbabilityException");
182 }
183 catch (ProbabilityException pe)
184 {
185
186 }
187
188 try
189 {
190 dist.get(2);
191 fail("Too high index should have thrown in a ProbabilityException");
192 }
193 catch (ProbabilityException pe)
194 {
195
196 }
197
198 dist.modifyFrequency(0, 5);
199 int[] observed = new int[2];
200 for (int i = 0; i < 10000; i++)
201 {
202 TestObject to3 = dist.draw();
203 if (to3.equals(to))
204 {
205 observed[0]++;
206 }
207 else if (to3.equals(to2))
208 {
209 observed[1]++;
210 }
211 else
212 {
213 fail("draw returned something we didn't add");
214 }
215 }
216
217
218 assertEquals("Total number of draws should add up to 10000", 10000, observed[0] + observed[1]);
219 assertTrue("observed frequency of to should be about 3333", 2500 < observed[0] && observed[0] < 4000);
220 dist.clear();
221 assertEquals("after clear the set should be empty", 0, dist.size());
222 try
223 {
224 dist.draw();
225 fail("Empty set should throw a ProbabilityException");
226 }
227 catch (ProbabilityException pe)
228 {
229
230 }
231
232 generators = new ArrayList<Distribution.FrequencyAndObject<TestObject>>();
233 generators.add(new FrequencyAndObject<DistributionTest.TestObject>(123, to));
234 generators.add(new FrequencyAndObject<DistributionTest.TestObject>(456, to2));
235 dist = new Distribution<TestObject>(generators, si);
236 assertEquals("element 0 should be to", to, dist.get(0).getObject());
237 assertEquals("element 1 should be to2", to2, dist.get(1).getObject());
238 assertEquals("frequency of element 0 should be 123", 123, dist.get(0).getFrequency(), 0.00001);
239 assertEquals("frequency of element 1 should be 456", 456, dist.get(1).getFrequency(), 0.00001);
240 generators.set(1, new FrequencyAndObject<DistributionTest.TestObject>(-1, to2));
241 try
242 {
243 new Distribution<TestObject>(generators, si);
244 fail("Negative frequency should have thrown a ProbabilityException");
245 }
246 catch (ProbabilityException pe)
247 {
248
249 }
250
251 try
252 {
253 dist.add(generators.get(1));
254 fail("Negative frequency should have thrown a ProbabilityException");
255 }
256 catch (ProbabilityException pe)
257 {
258
259 }
260
261 try
262 {
263 dist.set(-1, new FrequencyAndObject<DistributionTest.TestObject>(456, to2));
264 }
265 catch (ProbabilityException pe)
266 {
267
268 }
269
270 try
271 {
272 dist.set(dist.size(), new FrequencyAndObject<DistributionTest.TestObject>(456, to2));
273 }
274 catch (ProbabilityException pe)
275 {
276
277 }
278
279
280
281 double badTotal = 1000;
282 try
283 {
284 Field field = dist.getClass().getDeclaredField("cumulativeTotal");
285 field.setAccessible(true);
286 field.setDouble(dist, badTotal);
287 }
288 catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException exception)
289 {
290 exception.printStackTrace();
291 }
292
293 observed = new int[2];
294 for (int i = 0; i < 10000; i++)
295 {
296 TestObject to3 = dist.draw();
297 if (to3.equals(to))
298 {
299 observed[0]++;
300 }
301 else if (to3.equals(to2))
302 {
303 observed[1]++;
304 }
305 else
306 {
307 fail("draw returned something we didn't add");
308 }
309 }
310
311 double badFrequency = badTotal - dist.get(0).getFrequency() - dist.get(1).getFrequency();
312 double expectedIn0 = (dist.get(0).getFrequency() + badFrequency) / badTotal * 10000;
313
314 assertEquals("Total number of draws should add up to 10000", 10000, observed[0] + observed[1]);
315 assertTrue("observed frequency of to should be about " + expectedIn0,
316 expectedIn0 - 500 < observed[0] && observed[0] < expectedIn0 + 500);
317
318 dist.modifyFrequency(0, 0);
319 try
320 {
321 Field field = dist.getClass().getDeclaredField("cumulativeTotal");
322 field.setAccessible(true);
323 field.setDouble(dist, badTotal);
324 }
325 catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException exception)
326 {
327 exception.printStackTrace();
328 }
329
330 observed = new int[2];
331 for (int i = 0; i < 10000; i++)
332 {
333 TestObject to3 = dist.draw();
334 if (to3.equals(to))
335 {
336 observed[0]++;
337 }
338 else if (to3.equals(to2))
339 {
340 observed[1]++;
341 }
342 else
343 {
344 fail("draw returned something we didn't add");
345 }
346 }
347
348
349 assertEquals("Total number of draws should add up to 10000", 10000, observed[0] + observed[1]);
350 assertEquals("observed frequency of to should be 0", 0, observed[0]);
351 try
352 {
353 dist.modifyFrequency(dist.size(), 0);
354 }
355 catch (ProbabilityException pe)
356 {
357
358 }
359
360 try
361 {
362 dist.modifyFrequency(-1, 0);
363 }
364 catch (ProbabilityException pe)
365 {
366
367 }
368
369
370 dist.clear();
371 assertEquals("after clear the set should be empty", 0, dist.size());
372 }
373
374
375 class TestObject
376 {
377
378 }
379
380
381
382
383
384 @SuppressWarnings("unlikely-arg-type")
385 @Test
386 public void testHashCodeAndEquals() throws ProbabilityException
387 {
388 StreamInterface si = new MersenneTwister(1234);
389 Distribution<Double> distribution = new Distribution<>(si);
390 distribution.add(new FrequencyAndObject<Double>(Math.PI, 10d));
391 distribution.add(new FrequencyAndObject<Double>(2 * Math.PI, 20d));
392 assertTrue("distribution is equal to itself", distribution.equals(distribution));
393 assertFalse("distribution is not equal to null", distribution.equals(null));
394 assertFalse("distribution is not equal to something totally different", distribution.equals("junk"));
395 Distribution<Double> distribution2 = new Distribution<>(si);
396 assertFalse("Distribution is not equal to other distribution containing different set of frequency and object",
397 distribution.equals(distribution2));
398 distribution2.add(new FrequencyAndObject<Double>(Math.PI, 10d));
399 distribution2.add(new FrequencyAndObject<Double>(2 * Math.PI, 20d));
400
401
402
403
404 assertTrue("The toString method returns something descriptive", distribution.toString().startsWith("Distribution"));
405 }
406
407
408
409
410 @SuppressWarnings("unlikely-arg-type")
411 @Test
412 public void frequencyAndObjectTest()
413 {
414 FrequencyAndObject<String> fao1 = new FrequencyAndObject<>(Math.PI, "One");
415 assertEquals("frequency matches", Math.PI, fao1.getFrequency(), 0);
416 assertEquals("object matchs", "One", fao1.getObject());
417 assertTrue("FreqencyAndObject is equal to itself", fao1.equals(fao1));
418 assertFalse("FrequencyAndObject is not equal to null", fao1.equals(null));
419 assertFalse("FrequencyAndObject is not equal to some totally unrelated object", fao1.equals("Bla"));
420 FrequencyAndObject<String> fao2 = new FrequencyAndObject<>(Math.PI, "One");
421 assertTrue("FrequencyAndObject is equal to another FrequencyAndObject with same frequency and same object",
422 fao1.equals(fao2));
423 assertEquals("FrequencyAndObject has same hashCode as another FrequencyAndObject with same frequency and same object",
424 fao1.hashCode(), fao2.hashCode());
425 fao2 = new FrequencyAndObject<>(Math.PI, "Two");
426 assertFalse("FrequencyAndObject is not equal to another FrequencyAndObject with same frequency but other object",
427 fao1.equals(fao2));
428 fao2 = new FrequencyAndObject<>(Math.E, "One");
429 assertFalse("FrequencyAndObject is not equal to another FrequencyAndObject with different frequency but same object",
430 fao1.equals(fao2));
431 assertNotEquals("FrequencyAndObject has different hashCode than another FrequencyAndObject with different frequency "
432 + "and same object", fao1.hashCode(), fao2.hashCode());
433 fao2 = new FrequencyAndObject<>(Math.PI, null);
434 assertFalse("FrequencyAndObject is not equal to another FrequencyAndObject with same frequency but null object",
435 fao1.equals(fao2));
436 assertFalse("FrequencyAndObject is not equal to another FrequencyAndObject with same frequency but null object",
437 fao2.equals(fao1));
438 assertTrue("The toString methods returns something descriptive", fao1.toString().startsWith("FrequencyAndObject"));
439 }
440
441 }