1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.stat.descriptive.rank;
18
19 import org.hipparchus.UnitTestUtils;
20 import org.hipparchus.distribution.RealDistribution;
21 import org.hipparchus.distribution.continuous.ExponentialDistribution;
22 import org.hipparchus.distribution.continuous.GammaDistribution;
23 import org.hipparchus.distribution.continuous.LogNormalDistribution;
24 import org.hipparchus.distribution.continuous.NormalDistribution;
25 import org.hipparchus.exception.MathIllegalArgumentException;
26 import org.hipparchus.random.MersenneTwister;
27 import org.hipparchus.random.RandomDataGenerator;
28 import org.hipparchus.random.RandomGenerator;
29 import org.hipparchus.random.Well19937c;
30 import org.hipparchus.stat.StatUtils;
31 import org.hipparchus.stat.descriptive.StorelessUnivariateStatistic;
32 import org.hipparchus.stat.descriptive.StorelessUnivariateStatisticAbstractTest;
33 import org.hipparchus.stat.inference.AlternativeHypothesis;
34 import org.hipparchus.stat.inference.BinomialTest;
35 import org.hipparchus.util.FastMath;
36 import org.junit.jupiter.api.Test;
37
38 import java.lang.reflect.Constructor;
39 import java.lang.reflect.Method;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.List;
43 import java.util.SplittableRandom;
44
45 import static org.junit.jupiter.api.Assertions.assertEquals;
46 import static org.junit.jupiter.api.Assertions.assertFalse;
47 import static org.junit.jupiter.api.Assertions.assertThrows;
48 import static org.junit.jupiter.api.Assertions.assertTrue;
49
50
51
52
53
54 public class RandomPercentileTest extends
55 StorelessUnivariateStatisticAbstractTest {
56
57 protected double tolerance = 10E-12;
58
59 private final RandomGenerator randomGenerator = new Well19937c(1000);
60
61 @Override
62 public RandomPercentile getUnivariateStatistic() {
63 return new RandomPercentile();
64 }
65
66 @Override
67 public double expectedValue() {
68 return this.median;
69 }
70
71
72
73
74
75
76 @Test
77 void testCopyConsistencyWithInitialMostElements() {
78
79 StorelessUnivariateStatistic master = getUnivariateStatistic();
80 StorelessUnivariateStatistic replica = null;
81
82
83 long index = FastMath.round(0.75 * testArray.length);
84
85
86 master.incrementAll(testArray, 0, (int) index);
87 replica = master.copy();
88
89
90 assertEquals(replica, master);
91 assertEquals(master, replica);
92
93
94 master.incrementAll(testArray, (int) index, (int) (testArray.length - index));
95 replica.incrementAll(testArray, (int) index, (int) (testArray.length - index));
96 assertEquals(replica, master);
97 assertEquals(master, replica);
98 }
99
100
101
102
103
104
105 @Test
106 void testCopyConsistencyWithInitialFirstFewElements() {
107
108 StorelessUnivariateStatistic master = getUnivariateStatistic();
109 StorelessUnivariateStatistic replica = null;
110
111
112
113 long index = FastMath.round(0.1 * testArray.length);
114
115
116 master.incrementAll(testArray, 0, (int) index);
117 replica = master.copy();
118
119
120 assertEquals(replica, master);
121 assertEquals(master, replica);
122
123 master.incrementAll(testArray, (int) index, (int) (testArray.length - index));
124 replica.incrementAll(testArray, (int) index, (int) (testArray.length - index));
125 assertEquals(master, master);
126 assertEquals(replica, replica);
127 assertEquals(replica, master);
128 assertEquals(master, replica);
129 }
130
131 @Test
132 void testPercentileSmallSample() {
133 double[] d = new double[] { 1, 3, 2, 4 };
134 final RandomPercentile randomPercentile = new RandomPercentile();
135 randomPercentile.incrementAll(d);
136 Percentile p = new Percentile(30d);
137 assertEquals(p.evaluate(d), randomPercentile.getResult(30d), 1.0e-5);
138 p = new Percentile(25);
139 assertEquals(p.evaluate(d), randomPercentile.getResult(25d), 1.0e-5);
140 p = new Percentile(75);
141 assertEquals(p.evaluate(d),randomPercentile.getResult(75d), 1.0e-5);
142 p = new Percentile(50);
143 assertEquals(p.evaluate(d),randomPercentile.getResult(50d), 1.0e-5);
144 }
145
146 @Test
147 void testNonPositiveEpsilon() {
148 assertThrows(MathIllegalArgumentException.class, () -> {
149 double[] d =
150 new double[]{95.1772, 95.1567, 95.1937, 95.1959, 95.1442,
151 95.0610, 95.1591, 95.1195, 95.1772, 95.0925, 95.1990,
152 95.1682};
153 RandomPercentile p = new RandomPercentile(0);
154 p.evaluate(d, 0, d.length);
155 });
156 }
157
158 @Test
159 void testNISTExample() {
160 double[] d =
161 new double[] { 95.1772, 95.1567, 95.1937, 95.1959, 95.1442,
162 95.0610, 95.1591, 95.1195, 95.1772, 95.0925, 95.1990,
163 95.1682 };
164 assertEquals(95.1981, new RandomPercentile().evaluate(90d, d), 1.0e-4);
165 assertEquals(95.061, new RandomPercentile().evaluate(0d, d), 0);
166 assertEquals(95.1990, new RandomPercentile().evaluate(100d, d, 0, d.length), 0);
167 }
168
169 @Test
170 void test5() {
171 RandomPercentile percentile = new RandomPercentile();
172 assertEquals(this.percentile5, percentile.evaluate(5, testArray), 0.0001);
173 }
174
175 @Test
176 void testSingleton() {
177 RandomPercentile percentile = new RandomPercentile();
178 double[] singletonArray = new double[] { 1d };
179 assertEquals(1d, percentile.evaluate(singletonArray), 0);
180 assertEquals(1d, percentile.evaluate(singletonArray, 0, 1), 0);
181 percentile = new RandomPercentile();
182 assertEquals(1d, percentile.evaluate(5, singletonArray, 0, 1), 0);
183 percentile = new RandomPercentile();
184 assertEquals(1d, percentile.evaluate(100, singletonArray, 0, 1), 0);
185 percentile = new RandomPercentile();
186 assertTrue(Double.isNaN(percentile.evaluate(100, singletonArray, 0, 0)));
187 }
188
189 @Test
190 void testSpecialValues() {
191 RandomPercentile percentile = new RandomPercentile();
192 double[] specialValues = new double[] { 0d, 1d, 2d, 3d, 4d, Double.NaN };
193 assertEquals(2d, percentile.evaluate(specialValues), 0);
194 specialValues =
195 new double[] { Double.NEGATIVE_INFINITY, 1d, 2d, 3d, Double.NaN, Double.POSITIVE_INFINITY };
196 assertEquals(2d, percentile.evaluate(specialValues), 0);
197 specialValues =
198 new double[] { 1d, 1d, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY };
199 assertTrue(Double.isInfinite(percentile.evaluate(specialValues)));
200 specialValues = new double[] { 1d, 1d, Double.NaN, Double.NaN };
201 assertFalse(Double.isNaN(percentile.evaluate(specialValues)));
202 specialValues =
203 new double[] { 1d, 1d, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY };
204 percentile = new RandomPercentile();
205 assertTrue(Double.isNaN(percentile.evaluate(specialValues)));
206 }
207
208 @Test
209 void testAggregateSmallSamplesA() {
210 doTestAggregateSmallSamples(0.5, 11.0);
211 }
212
213 @Test
214 void testAggregateSmallSamplesB() {
215 doTestAggregateSmallSamples(0.1, 7.0);
216 }
217
218 @Test
219 void testAggregateSmallSamplesC() {
220 doTestAggregateSmallSamples(0.01, 7.0);
221 }
222
223 private void doTestAggregateSmallSamples(double epsilon, double expected) {
224 SplittableRandom seeds = new SplittableRandom(0x218560e08c8df220l);
225
226 RandomPercentile rp1 = new RandomPercentile(epsilon, new Well19937c(seeds.nextLong()));
227 double[] data1 = new double[] { 3, 5, -2, 7, 14, 6 };
228 for (double d : data1 ) {
229 rp1.accept(d);
230 }
231 RandomPercentile rp2 = new RandomPercentile(epsilon, new Well19937c(seeds.nextLong()));
232 double[] data2 = new double[] { 9, 12, 15 };
233 for (double d : data2 ) {
234 rp2.accept(d);
235 }
236
237 rp1.aggregate(rp2);
238
239 assertEquals(expected, rp1.getResult(), 1.0e-10);
240
241 }
242
243 @Test
244 void testBufferConsumeLevel0() throws Exception {
245 final int len = testArray.length;
246 final double[] sorted = Arrays.copyOf(testArray, len);
247 Arrays.sort(sorted);
248 BufferMock buffer = new BufferMock(len, 0, randomGenerator);
249 for (int i = 0; i < len; i++) {
250 buffer.consume(testArray[i]);
251 }
252 UnitTestUtils.customAssertEquals(sorted, buffer.getData(), Double.MIN_VALUE);
253 assertFalse(buffer.hasCapacity());
254 assertEquals(StatUtils.min(testArray),buffer.min(), Double.MIN_VALUE);
255 assertEquals(StatUtils.max(testArray),buffer.max(), Double.MIN_VALUE);
256 }
257
258 @Test
259 void testBufferSampling() throws Exception {
260
261 BufferMock buffer = new BufferMock(10, 2, randomGenerator);
262 for (int i = 0; i < 40; i++) {
263 buffer.consume(i);
264 }
265
266 assertFalse(buffer.hasCapacity());
267 final double[] data = buffer.getData();
268 for (int i = 0; i < 10; i++) {
269 assertTrue(data[i] < 4 * (i + 1));
270 assertTrue(data[i] >= 4 * i);
271
272 assertEquals(i + 1, buffer.rankOf((i + 1) * 4));
273
274 assertEquals(0, buffer.rankOf(-1));
275 assertEquals(10, buffer.rankOf(100));
276 }
277 }
278
279 @Test
280 void testBufferMergeWith() throws Exception {
281
282 BufferMock buffer1 = new BufferMock(20, 0, randomGenerator);
283 BufferMock buffer2 = new BufferMock(20, 0, randomGenerator);
284
285
286 for (int i = 0; i < 20; i++) {
287 buffer1.consume(i);
288 buffer2.consume(i + 20);
289 }
290 assertEquals(0, buffer1.getLevel());
291 assertEquals(0, buffer2.getLevel());
292
293
294 buffer1.mergeWith(buffer2.getInstance());
295
296
297 assertEquals(1,buffer1.getLevel());
298 assertFalse(buffer1.hasCapacity());
299 assertEquals(1,buffer2.getLevel());
300 assertTrue(buffer2.hasCapacity());
301
302
303 final double[] data = buffer1.getData();
304 int nSmall = 0;
305 for (double value : data) {
306 assertTrue(value >=0 && value < 40);
307 if (value < 20) {
308 nSmall++;
309 }
310 }
311
312
313 BinomialTest bTest = new BinomialTest();
314 assertFalse(bTest.binomialTest(20, nSmall, 0.5, AlternativeHypothesis.TWO_SIDED, 0.01));
315
316
317 buffer1.checkSorted();
318 }
319
320 @Test
321 void testBufferMergeInto() throws Exception {
322 BufferMock buffer1 = new BufferMock(20, 0, randomGenerator);
323 BufferMock buffer2 = new BufferMock(20, 2, randomGenerator);
324
325
326 for (int i = 0; i < 20; i++) {
327 buffer1.consume(i);
328 }
329
330
331 for (int i = 0; i < 80; i++) {
332 buffer2.consume(i + 20);
333 }
334 assertFalse(buffer1.hasCapacity());
335 assertFalse(buffer2.hasCapacity());
336 buffer1.mergeInto(buffer2.getInstance());
337
338
339 assertEquals(0, buffer1.getLevel());
340 assertEquals(2, buffer2.getLevel());
341
342
343 final double[] data = buffer2.getData();
344 int nSmall = 0;
345 for (double value : data) {
346 assertTrue(value >=0 && value < 100);
347 if (value < 20) {
348 nSmall++;
349 }
350 }
351 BinomialTest bTest = new BinomialTest();
352 assertFalse(bTest.binomialTest(20, nSmall, 0.25, AlternativeHypothesis.TWO_SIDED, 0.01));
353
354
355 buffer2.checkSorted();
356 }
357
358 static class BufferMock {
359 private Object instance;
360 private Method consumeMethod;
361 private Method getDataMethod;
362 private Method hasCapacityMethod;
363 private Method minMethod;
364 private Method maxMethod;
365 private Method rankOfMethod;
366 private Method getLevelMethod;
367 private Method mergeWithMethod;
368 private Method mergeIntoMethod;
369 @SuppressWarnings({ "unchecked", "rawtypes" })
370 public BufferMock(int size, int level, RandomGenerator randomGenerator) throws Exception {
371 final Class[] classes = RandomPercentile.class.getDeclaredClasses();
372 for (Class cls : classes) {
373 if (cls.getName().endsWith("$Buffer")) {
374 Constructor constructor = cls.getDeclaredConstructor(Integer.TYPE, Integer.TYPE, RandomGenerator.class);
375 instance = constructor.newInstance(size, level, randomGenerator);
376 consumeMethod = cls.getDeclaredMethod("consume", Double.TYPE);
377 getDataMethod = cls.getDeclaredMethod("getData");
378 hasCapacityMethod = cls.getDeclaredMethod("hasCapacity");
379 minMethod = cls.getDeclaredMethod("min");
380 maxMethod = cls.getDeclaredMethod("max");
381 rankOfMethod = cls.getDeclaredMethod("rankOf", Double.TYPE);
382 getLevelMethod = cls.getDeclaredMethod("getLevel");
383 mergeWithMethod = cls.getDeclaredMethod("mergeWith", cls);
384 mergeIntoMethod = cls.getDeclaredMethod("mergeInto", cls);
385 }
386 }
387 }
388
389 public void consume(double value) throws Exception {
390 consumeMethod.invoke(instance, value);
391 }
392
393 public boolean hasCapacity() throws Exception {
394 return (boolean) hasCapacityMethod.invoke(instance);
395 }
396
397 public double[] getData() throws Exception {
398 return (double[]) getDataMethod.invoke(instance);
399 }
400
401 public double min() throws Exception {
402 return (double) minMethod.invoke(instance);
403 }
404
405 public double max() throws Exception {
406 return (double) maxMethod.invoke(instance);
407 }
408
409 public int rankOf(double value) throws Exception {
410 return (int) rankOfMethod.invoke(instance, value);
411 }
412
413 public int getLevel() throws Exception {
414 return (int) getLevelMethod.invoke(instance);
415 }
416
417 public void mergeWith(Object other) throws Exception {
418 mergeWithMethod.invoke(instance, other);
419 }
420
421 public void mergeInto(Object other) throws Exception {
422 mergeIntoMethod.invoke(instance, other);
423 }
424
425 public Object getInstance() {
426 return instance;
427 }
428
429 public void checkSorted() throws Exception {
430 final double[] data = getData();
431 final double[] copy = Arrays.copyOf(data, data.length);
432 Arrays.sort(copy);
433 UnitTestUtils.customAssertEquals(data, copy, Double.MIN_VALUE);
434 }
435
436 }
437
438 @Test
439 void testArrayExample() {
440 assertEquals(this.percentile95, new RandomPercentile().evaluate(95d,testArray), getTolerance());
441 }
442
443 @Test
444 void testReduceSmallDataSet() {
445 final RandomDataGenerator random = new RandomDataGenerator(1000);
446 final long n = 1000;
447 double[] combined = new double[10000];
448 int i = 0;
449 final List<RandomPercentile> aggregates = new ArrayList<RandomPercentile>();
450 for (int j = 0; j < 10; j++) {
451 final RandomPercentile randomPercentile = new RandomPercentile();
452 for (int k = 0; k < n; k++) {
453 final double value = random.nextGaussian();
454 randomPercentile.accept(value);
455 combined[i++] = value;
456 }
457 aggregates.add(randomPercentile);
458 }
459
460 final Percentile master = new Percentile();
461 final RandomPercentile randomMaster = new RandomPercentile();
462 for (int l = 0; l < 5; l++) {
463 final double percentile = l * 15 + 1;
464 assertEquals(master.evaluate(combined, percentile),
465 randomMaster.reduce(percentile, aggregates), Double.MIN_VALUE);
466 }
467 }
468
469 @Test
470 void testReduceLargeDataSet() {
471 final RandomDataGenerator random = new RandomDataGenerator(1000);
472 final long n = 1000000;
473 final RandomGenerator randomGenerator = new RandomDataGenerator(1000);
474 final RandomPercentile randomMaster = new RandomPercentile(randomGenerator);
475 final PSquarePercentile pSquare = new PSquarePercentile(1);
476 final List<RandomPercentile> aggregates = new ArrayList<RandomPercentile>();
477 for (int j = 0; j < 5; j++) {
478 final RandomPercentile randomPercentile = new RandomPercentile(randomGenerator);
479 for (int k = 0; k < n; k++) {
480 final double value = random.nextGaussian();
481 randomPercentile.accept(value);
482 randomMaster.accept(value);
483 pSquare.increment(value);
484 }
485 aggregates.add(randomPercentile);
486 }
487
488 for (int l = 0; l < 5; l++) {
489 final double percentile = l * 13 + 1;
490 assertEquals(randomMaster.getResult(percentile),
491 randomMaster.reduce(percentile, aggregates), 5E-3, "percentile = " + percentile);
492 }
493 }
494
495 private Double[] randomTestData(int factor, int values) {
496 Double[] test = new Double[values];
497 for (int i = 0; i < test.length; i++) {
498 test[i] = Math.abs(randomGenerator.nextDouble() * factor);
499 }
500 return test;
501 }
502
503
504 public void testAccept() {
505 final RandomPercentile randomPercentile = new RandomPercentile();
506 assertTrue(Double.isNaN(randomPercentile.getResult()));
507 Double[] test = randomTestData(100, 10000);
508
509 for (Double value : test) {
510 randomPercentile.increment(value);
511 assertTrue(randomPercentile.getResult() >= 0);
512 }
513 }
514
515 private void customAssertValues(Double a, Double b, double delta) {
516 if (Double.isNaN(a)) {
517 assertTrue(Double.isNaN(a), "" + b + " is not NaN.");
518 } else if (Double.isInfinite(a)) {
519 assertEquals(a, b);
520 } else {
521 double max = FastMath.max(a, b);
522 double percentage = FastMath.abs(a - b) / max;
523 double deviation = delta;
524 assertTrue(percentage < deviation, String.format("Deviated = %f and is beyond %f as a=%f, b=%f",
525 percentage, deviation, a, b));
526 }
527 }
528
529
530
531
532
533
534
535
536
537
538 private void checkQuantileError(double[] data, double value, double quantile, double tolerance,
539 double referenceValue) {
540 final double n = (double) data.length;
541 int nLess = 0;
542 for (double val : data) {
543 if (val < value) {
544 nLess++;
545 }
546 }
547 if (Double.isNaN(referenceValue)) {
548 assertTrue(Double.isNaN(value));
549 } else if (Double.isInfinite(value)) {
550 assertEquals(value, referenceValue);
551 } else {
552 assertTrue(FastMath.abs(quantile - (double) nLess / n) < tolerance,
553 "Quantile error exceeded: value returned = " + value +
554 " Reference value = " + referenceValue +
555 " quantile = " + quantile + " n = " + n +
556 " error = " + (quantile - (double) nLess / n));
557 }
558 }
559
560
561 private void doCalculatePercentile(Double percentile, Number[] test) {
562 doCalculatePercentile(percentile, test, Double.MAX_VALUE);
563 }
564
565
566 private void doCalculatePercentile(Double percentile, Number[] test, double delta) {
567 RandomPercentile random = new RandomPercentile(new Well19937c(200));
568 for (Number value : test) {
569 random.increment(value.doubleValue());
570 }
571
572 Percentile p2 = new Percentile(percentile * 100);
573
574 double[] dall = new double[test.length];
575 for (int i = 0; i < test.length; i++) {
576 dall[i] = test[i].doubleValue();
577 }
578
579 Double referenceValue = p2.evaluate(dall);
580 customAssertValues(random.getResult(percentile), referenceValue, delta);
581 }
582
583 private void doCalculatePercentile(double percentile, double[] test, double delta) {
584 RandomPercentile randomEstimated = new RandomPercentile(new Well19937c(200));
585 for (double value : test) {
586 randomEstimated.increment(value);
587 }
588
589 Percentile p2 = new Percentile(percentile < 1 ? percentile * 100 : percentile);
590
591
592
593
594 Double referenceValue = p2.evaluate(test);
595 if (test.length < LARGE) {
596 customAssertValues(randomEstimated.getResult(percentile), referenceValue, delta);
597 } else {
598 checkQuantileError(test,randomEstimated.getResult(percentile), percentile / 100, delta, referenceValue);
599 }
600 }
601
602 @Test
603 void testCannedDataSet() {
604 Integer[] seedInput =
605 new Integer[] { 283, 285, 298, 304, 310, 31, 319, 32, 33, 339,
606 342, 348, 350, 354, 354, 357, 36, 36, 369, 37, 37, 375,
607 378, 383, 390, 396, 405, 408, 41, 414, 419, 416, 42,
608 420, 430, 430, 432, 444, 447, 447, 449, 45, 451, 456,
609 468, 470, 471, 474, 600, 695, 70, 83, 97, 109, 113, 128 };
610 Integer[] input = new Integer[seedInput.length * 100];
611 for (int i = 0; i < input.length; i++) {
612 input[i] = seedInput[i % seedInput.length] + i;
613 }
614 doCalculatePercentile(0.50d, input);
615 doCalculatePercentile(0.95d, input);
616 }
617
618 @Test
619 void test99Percentile() {
620 Double[] test = randomTestData(100, 10000);
621 doCalculatePercentile(0.99d, test);
622 }
623
624 @Test
625 void test90Percentile() {
626 Double[] test = randomTestData(100, 10000);
627 doCalculatePercentile(0.90d, test);
628 }
629
630 @Test
631 void test20Percentile() {
632 Double[] test = randomTestData(100, 100000);
633 doCalculatePercentile(0.20d, test);
634 }
635
636 @Test
637 void test5Percentile() {
638 Double[] test = randomTestData(50, 990000);
639 doCalculatePercentile(0.50d, test);
640 }
641
642 @Test
643 void test99PercentileHighValues() {
644 Double[] test = randomTestData(100000, 10000);
645 doCalculatePercentile(0.99d, test);
646 }
647
648 @Test
649 void test90PercentileHighValues() {
650 Double[] test = randomTestData(100000, 100000);
651 doCalculatePercentile(0.90d, test);
652 }
653
654 @Test
655 void test20PercentileHighValues() {
656 Double[] test = randomTestData(100000, 100000);
657 doCalculatePercentile(0.20d, test);
658 }
659
660 @Test
661 void test5PercentileHighValues() {
662 Double[] test = randomTestData(100000, 100000);
663 doCalculatePercentile(0.05d, test);
664 }
665
666 @Test
667 void test0PercentileValuesWithFewerThan5Values() {
668 double[] test = { 1d, 2d, 3d, 4d };
669 RandomPercentile p = new RandomPercentile();
670 assertEquals(1d, p.evaluate(0d,test), 0);
671 }
672
673 @Test
674 void testMaxValuesRetained() {
675 assertEquals(546795, RandomPercentile.maxValuesRetained(RandomPercentile.DEFAULT_EPSILON));
676 assertEquals(34727, RandomPercentile.maxValuesRetained(1E-3));
677 assertEquals(2064, RandomPercentile.maxValuesRetained(1E-2));
678 }
679
680 @Test
681 void testMaxValuesRetained0Epsilon() {
682 assertThrows(MathIllegalArgumentException.class, () -> {
683 RandomPercentile.maxValuesRetained(0);
684 });
685 }
686
687 @Test
688 void testMaxValuesRetained1Epsilon() {
689 assertThrows(MathIllegalArgumentException.class, () -> {
690 RandomPercentile.maxValuesRetained(1);
691 });
692 }
693
694
695 final int TINY = 10, SMALL = 50, NOMINAL = 100, MEDIUM = 500,
696 STANDARD = 1000, BIG = 10000, VERY_BIG = 50000, LARGE = 1000000,
697 VERY_LARGE = 10000000;
698
699 private void doDistributionTest(RealDistribution distribution) {
700 double[] data;
701
702 final RandomDataGenerator randomDataGenerator = new RandomDataGenerator(100);
703 data = randomDataGenerator.nextDeviates(distribution, LARGE);
704 doCalculatePercentile(50, data, 0.0005);
705 doCalculatePercentile(95, data, 0.0005);
706
707 data = randomDataGenerator.nextDeviates(distribution, VERY_BIG);
708 doCalculatePercentile(50, data, 0.0001);
709 doCalculatePercentile(95, data, 0.0001);
710
711 data = randomDataGenerator.nextDeviates(distribution, BIG);
712 doCalculatePercentile(50, data, 0.0001);
713 doCalculatePercentile(95, data, 0.0001);
714
715 data = randomDataGenerator.nextDeviates(distribution, STANDARD);
716 doCalculatePercentile(50, data, 0.0001);
717 doCalculatePercentile(95, data, 0.0001);
718
719 data = randomDataGenerator.nextDeviates(distribution, MEDIUM);
720 doCalculatePercentile(50, data, 0.0001);
721 doCalculatePercentile(95, data, 0.0001);
722
723 data = randomDataGenerator.nextDeviates(distribution, NOMINAL);
724 doCalculatePercentile(50, data, 0.0001);
725 doCalculatePercentile(95, data, 0.0001);
726
727 data = randomDataGenerator.nextDeviates(distribution, SMALL);
728 doCalculatePercentile(50, data, 0.0001);
729 doCalculatePercentile(95, data, 0.0001);
730
731 data = randomDataGenerator.nextDeviates(distribution, TINY);
732 doCalculatePercentile(50, data, 0.0001);
733 doCalculatePercentile(95, data, 0.0001);
734 }
735
736
737
738
739 @Test
740 void testDistribution() {
741 doDistributionTest(new NormalDistribution(4000, 50));
742 doDistributionTest(new LogNormalDistribution(4000, 50));
743 doDistributionTest(new ExponentialDistribution(4000));
744 doDistributionTest(new GammaDistribution(5d,1d));
745 }
746
747
748
749
750 @Test
751 void testDistributionStreaming() {
752 checkQuartiles(new NormalDistribution(), 1000000, 5E-4);
753 checkQuartiles(new ExponentialDistribution(1), 600000, 5E-4);
754 checkQuartiles(new GammaDistribution(4d,2d), 600000, 5E-4);
755 }
756
757
758
759
760 @Test
761 void testSequentialData() {
762 final long seed = 1000;
763 double epsilon = 1e-4;
764 for (int j = 0; j < 3; j++) {
765 epsilon *= 10;
766 final RandomPercentile randomPercentile = new RandomPercentile(epsilon,
767 new MersenneTwister(seed));
768 final int n = 5000000;
769 for (int i = 1; i <= n; i++) {
770 randomPercentile.accept(i);
771 }
772 for (int i = 1; i < 5; i++) {
773 assertEquals(0.2 * i, randomPercentile.getResult(i * 20) / n, 2 * epsilon);
774 }
775 }
776 }
777
778
779
780
781
782
783
784
785 private void checkQuartiles(RealDistribution dist, int sampleSize, double tolerance) {
786 final long seed = 1000;
787 RandomDataGenerator randomDataGenerator = RandomDataGenerator.of(new MersenneTwister(seed));
788 final RandomPercentile randomPercentile = new RandomPercentile(RandomPercentile.DEFAULT_EPSILON,
789 randomGenerator);
790 for (int i = 0; i < sampleSize; i++) {
791 randomPercentile.increment(randomDataGenerator.nextDeviate(dist));
792 }
793 final double q1 = randomPercentile.getResult(25);
794 final double q2 = randomPercentile.getResult();
795 final double q3 = randomPercentile.getResult(75);
796
797
798 randomDataGenerator.setSeed(seed);
799 double v;
800 double ct1 = 0;
801 double ct2 = 0;
802 double ct3 = 0;
803 for (int i = 0; i < sampleSize; i++) {
804 v = randomDataGenerator.nextDeviate(dist);
805 if (v < q1) {
806 ct1++;
807 ct2++;
808 ct3++;
809 } else if (v < q2) {
810 ct2++;
811 ct3++;
812 } else if (v < q3) {
813 ct3++;
814 }
815 }
816 assertEquals(0.25, ct1/sampleSize, tolerance);
817 assertEquals(0.5, ct2/sampleSize, tolerance);
818 assertEquals(0.75, ct3/sampleSize, tolerance);
819 }
820 }