View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.stat.descriptive;
23  
24  import org.hipparchus.UnitTestUtils;
25  import org.hipparchus.distribution.RealDistribution;
26  import org.hipparchus.distribution.continuous.UniformRealDistribution;
27  import org.hipparchus.random.RandomDataGenerator;
28  import org.hipparchus.random.Well19937a;
29  import org.hipparchus.util.FastMath;
30  import org.junit.jupiter.api.Test;
31  
32  import java.util.Arrays;
33  
34  import static org.junit.jupiter.api.Assertions.assertEquals;
35  import static org.junit.jupiter.api.Assertions.assertFalse;
36  import static org.junit.jupiter.api.Assertions.assertNotEquals;
37  import static org.junit.jupiter.api.Assertions.assertTrue;
38  
39  /**
40   * Test cases for the {@link StreamingStatistics} class.
41   */
42  class StreamingStatisticsTest {
43  
44      private final double[] testArray = new double[] { 1, 2, 2, 3 };
45  
46      private final double one = 1;
47      private final float twoF = 2;
48  
49      private final double mean = 2;
50      private final double sumSq = 18;
51      private final double sum = 8;
52      private final double var = 0.666666666666666666667;
53      private final double popVar = 0.5;
54      private final double std = FastMath.sqrt(var);
55      private final double n = 4;
56      private final double min = 1;
57      private final double max = 3;
58      private final double tolerance = 10E-15;
59  
60      protected StreamingStatistics createStreamingStatistics() {
61          return new StreamingStatistics();
62      }
63  
64      /** test stats */
65      @Test
66      void testStats() {
67          StreamingStatistics u = createStreamingStatistics();
68          assertEquals(0, u.getN(), tolerance, "total count");
69          u.addValue(one);
70          u.addValue(twoF);
71          long twoL = 2;
72          u.addValue(twoL);
73          int three = 3;
74          u.addValue(three);
75          assertEquals(n, u.getN(), tolerance, "N");
76          assertEquals(sum, u.getSum(), tolerance, "sum");
77          assertEquals(sumSq, u.getSumOfSquares(), tolerance, "sumsq");
78          assertEquals(var, u.getVariance(), tolerance, "var");
79          assertEquals(popVar, u.getPopulationVariance(), tolerance, "population var");
80          assertEquals(std, u.getStandardDeviation(), tolerance, "std");
81          assertEquals(mean, u.getMean(), tolerance, "mean");
82          assertEquals(min, u.getMin(), tolerance, "min");
83          assertEquals(max, u.getMax(), tolerance, "max");
84          u.clear();
85          assertEquals(0, u.getN(), tolerance, "total count");
86      }
87  
88      @Test
89      void testConsume() {
90          StreamingStatistics u = createStreamingStatistics();
91          assertEquals(0, u.getN(), tolerance, "total count");
92  
93          Arrays.stream(testArray)
94                .forEach(u);
95  
96          assertEquals(n, u.getN(), tolerance, "N");
97          assertEquals(sum, u.getSum(), tolerance, "sum");
98          assertEquals(sumSq, u.getSumOfSquares(), tolerance, "sumsq");
99          assertEquals(var, u.getVariance(), tolerance, "var");
100         assertEquals(popVar, u.getPopulationVariance(), tolerance, "population var");
101         assertEquals(std, u.getStandardDeviation(), tolerance, "std");
102         assertEquals(mean, u.getMean(), tolerance, "mean");
103         assertEquals(min, u.getMin(), tolerance, "min");
104         assertEquals(max, u.getMax(), tolerance, "max");
105         u.clear();
106         assertEquals(0, u.getN(), tolerance, "total count");
107     }
108 
109     @Test
110     void testN0andN1Conditions() {
111         StreamingStatistics u = createStreamingStatistics();
112         assertTrue(Double.isNaN( u.getMean() ), "Mean of n = 0 set should be NaN" );
113         assertTrue(Double.isNaN( u.getStandardDeviation() ),
114                    "Standard Deviation of n = 0 set should be NaN" );
115         assertTrue(Double.isNaN(u.getVariance() ), "Variance of n = 0 set should be NaN" );
116 
117         /* n=1 */
118         u.addValue(one);
119         assertEquals(u.getMean(), one, "mean should be one (n = 1)");
120         assertEquals(u.getGeometricMean(), one, "geometric should be one (n = 1) instead it is " + u.getGeometricMean());
121         assertEquals(0.0, u.getStandardDeviation(), "Std should be zero (n = 1)");
122         assertEquals(0.0, u.getVariance(), "variance should be zero (n = 1)");
123 
124         /* n=2 */
125         u.addValue(twoF);
126         assertTrue(u.getStandardDeviation() != 0.0, "Std should not be zero (n = 2)");
127         assertTrue(u.getVariance() != 0.0, "variance should not be zero (n = 2)");
128     }
129 
130     @Test
131     void testProductAndGeometricMean() {
132         StreamingStatistics u = createStreamingStatistics();
133         u.addValue( 1.0 );
134         u.addValue( 2.0 );
135         u.addValue( 3.0 );
136         u.addValue( 4.0 );
137 
138         assertEquals( 2.213364, u.getGeometricMean(), 0.00001, "Geometric mean not expected" );
139     }
140 
141     @Test
142     void testNaNContracts() {
143         StreamingStatistics u = createStreamingStatistics();
144         assertTrue(Double.isNaN(u.getMean()),"mean not NaN");
145         assertTrue(Double.isNaN(u.getMin()),"min not NaN");
146         assertTrue(Double.isNaN(u.getStandardDeviation()),"std dev not NaN");
147         assertTrue(Double.isNaN(u.getVariance()),"var not NaN");
148         assertTrue(Double.isNaN(u.getGeometricMean()),"geom mean not NaN");
149 
150         u.addValue(1.0);
151 
152         assertEquals(1.0, u.getMean(), Double.MIN_VALUE, "mean");
153         assertEquals(0.0, u.getVariance(), Double.MIN_VALUE, "variance");
154         assertEquals(1.0, u.getGeometricMean(), Double.MIN_VALUE, "geometric mean");
155 
156         u.addValue(-1.0);
157 
158         assertTrue(Double.isNaN(u.getGeometricMean()),"geom mean not NaN");
159 
160         u.addValue(0.0);
161 
162         assertTrue(Double.isNaN(u.getGeometricMean()),"geom mean not NaN");
163 
164         //FiXME: test all other NaN contract specs
165     }
166 
167     @Test
168     void testGetSummary() {
169         StreamingStatistics u = createStreamingStatistics();
170         StatisticalSummary summary = u.getSummary();
171         verifySummary(u, summary);
172         u.addValue(1d);
173         summary = u.getSummary();
174         verifySummary(u, summary);
175         u.addValue(2d);
176         summary = u.getSummary();
177         verifySummary(u, summary);
178         u.addValue(2d);
179         summary = u.getSummary();
180         verifySummary(u, summary);
181     }
182 
183     @Test
184     void testSerialization() {
185         StreamingStatistics u = createStreamingStatistics();
186         // Empty test
187         UnitTestUtils.checkSerializedEquality(u);
188         StreamingStatistics s = (StreamingStatistics) UnitTestUtils.serializeAndRecover(u);
189         StatisticalSummary summary = s.getSummary();
190         verifySummary(u, summary);
191 
192         // Add some data
193         u.addValue(2d);
194         u.addValue(1d);
195         u.addValue(3d);
196         u.addValue(4d);
197         u.addValue(5d);
198 
199         // Test again
200         UnitTestUtils.checkSerializedEquality(u);
201         s = (StreamingStatistics) UnitTestUtils.serializeAndRecover(u);
202         summary = s.getSummary();
203         verifySummary(u, summary);
204     }
205 
206     @SuppressWarnings("unlikely-arg-type")
207     @Test
208     void testEqualsAndHashCode() {
209         StreamingStatistics u = createStreamingStatistics();
210         StreamingStatistics t = null;
211         int emptyHash = u.hashCode();
212         assertEquals(u, u, "reflexive");
213         assertNotEquals(u, t, "non-null compared to null");
214         assertNotEquals(u, Double.valueOf(0), "wrong type");
215         t = createStreamingStatistics();
216         assertEquals(t, u, "empty instances should be equal");
217         assertEquals(u, t, "empty instances should be equal");
218         assertEquals(emptyHash, t.hashCode(), "empty hash code");
219 
220         // Add some data to u
221         u.addValue(2d);
222         u.addValue(1d);
223         u.addValue(3d);
224         u.addValue(4d);
225         assertNotEquals(t, u, "different n's should make instances not equal");
226         assertNotEquals(u, t, "different n's should make instances not equal");
227         assertTrue(u.hashCode() != t.hashCode(), "different n's should make hashcodes different");
228 
229         //Add data in same order to t
230         t.addValue(2d);
231         t.addValue(1d);
232         t.addValue(3d);
233         t.addValue(4d);
234         assertEquals(t, u, "summaries based on same data should be equal");
235         assertEquals(u, t, "summaries based on same data should be equal");
236         assertEquals(u.hashCode(), t.hashCode(), "summaries based on same data should have same hashcodes");
237 
238         // Clear and make sure summaries are indistinguishable from empty summary
239         u.clear();
240         t.clear();
241         assertEquals(t, u, "empty instances should be equal");
242         assertEquals(u, t, "empty instances should be equal");
243         assertEquals(emptyHash, t.hashCode(), "empty hash code");
244         assertEquals(emptyHash, u.hashCode(), "empty hash code");
245     }
246 
247     @Test
248     void testCopy() {
249         StreamingStatistics u = createStreamingStatistics();
250         u.addValue(2d);
251         u.addValue(1d);
252         u.addValue(3d);
253         u.addValue(4d);
254         StreamingStatistics v = u.copy();
255         assertEquals(u, v);
256         assertEquals(v, u);
257 
258         // Make sure both behave the same with additional values added
259         u.addValue(7d);
260         u.addValue(9d);
261         u.addValue(11d);
262         u.addValue(23d);
263         v.addValue(7d);
264         v.addValue(9d);
265         v.addValue(11d);
266         v.addValue(23d);
267         assertEquals(u, v);
268         assertEquals(v, u);
269     }
270 
271     private void verifySummary(StreamingStatistics u, StatisticalSummary s) {
272         assertEquals(s.getN(),u.getN(),"N");
273         UnitTestUtils.customAssertEquals("sum", s.getSum(), u.getSum(), tolerance);
274         UnitTestUtils.customAssertEquals("var", s.getVariance(), u.getVariance(), tolerance);
275         UnitTestUtils.customAssertEquals("std", s.getStandardDeviation(), u.getStandardDeviation(), tolerance);
276         UnitTestUtils.customAssertEquals("mean", s.getMean(), u.getMean(), tolerance);
277         UnitTestUtils.customAssertEquals("min", s.getMin(), u.getMin(), tolerance);
278         UnitTestUtils.customAssertEquals("max", s.getMax(), u.getMax(), tolerance);
279     }
280 
281     @Test
282     void testQuadraticMean() {
283         final double[] values = { 1.2, 3.4, 5.6, 7.89 };
284         final StreamingStatistics stats = createStreamingStatistics();
285 
286         final int len = values.length;
287         double expected = 0;
288         for (int i = 0; i < len; i++) {
289             final double v = values[i];
290             expected += v * v / len;
291 
292             stats.addValue(v);
293         }
294         expected = Math.sqrt(expected);
295 
296         assertEquals(expected, stats.getQuadraticMean(), Math.ulp(expected));
297     }
298 
299     @Test
300     void testToString() {
301         StreamingStatistics u = createStreamingStatistics();
302         for (int i = 0; i < 5; i++) {
303             u.addValue(i);
304         }
305         final String[] labels = {
306             "min", "max", "sum", "geometric mean", "variance", "population variance",
307             "second moment", "sum of squares", "standard deviation", "sum of logs"
308         };
309         final double[] values = {
310             u.getMin(), u.getMax(), u.getSum(), u.getGeometricMean(), u.getVariance(),
311             u.getPopulationVariance(), u.getSecondMoment(), u.getSumOfSquares(),
312             u.getStandardDeviation(), u.getSumOfLogs()
313         };
314         final String toString = u.toString();
315         assertTrue(toString.indexOf("n: " + u.getN()) > 0); // getN() returns a long
316         for (int i = 0; i < values.length; i++) {
317             assertTrue(toString.indexOf(labels[i] + ": " + String.valueOf(values[i])) > 0);
318         }
319     }
320 
321     /**
322      * Verify that aggregating over a partition gives the same results
323      * as direct computation.
324      *
325      *  1) Randomly generate a dataset of 10-100 values
326      *     from [-100, 100]
327      *  2) Divide the dataset it into 2-5 partitions
328      *  3) Create an AggregateSummaryStatistic and ContributingStatistics
329      *     for each partition
330      *  4) Compare results from the AggregateSummaryStatistic with values
331      *     returned by a single SummaryStatistics instance that is provided
332      *     the full dataset
333      */
334     @Test
335     void testAggregationConsistency() {
336 
337         // Generate a random sample and random partition
338         double[] totalSample = generateSample();
339         double[][] subSamples = generatePartition(totalSample);
340         int nSamples = subSamples.length;
341 
342         // Create aggregator and total stats for comparison
343         StreamingStatistics aggregate = new StreamingStatistics();
344         StreamingStatistics totalStats = new StreamingStatistics();
345 
346         // Create array of component stats
347         StreamingStatistics[] componentStats = new StreamingStatistics[nSamples];
348 
349         for (int i = 0; i < nSamples; i++) {
350 
351             // Make componentStats[i] a contributing statistic to aggregate
352             componentStats[i] = new StreamingStatistics();
353 
354             // Add values from subsample
355             for (int j = 0; j < subSamples[i].length; j++) {
356                 componentStats[i].addValue(subSamples[i][j]);
357             }
358         }
359 
360         aggregate.aggregate(componentStats);
361 
362         // Compute totalStats directly
363         for (int i = 0; i < totalSample.length; i++) {
364             totalStats.addValue(totalSample[i]);
365         }
366 
367         /*
368          * Compare statistics in totalStats with aggregate.
369          * Note that guaranteed success of this comparison depends on the
370          * fact that <aggregate> gets values in exactly the same order
371          * as <totalStats>.
372          */
373         customAssertSummaryStatisticsEquals(totalStats, aggregate, 1e-10);
374 
375         // Check some percentiles
376         final double tol = 1e-13;
377         assertEquals(totalStats.getPercentile(10), aggregate.getPercentile(10), tol);
378         assertEquals(totalStats.getPercentile(25), aggregate.getPercentile(25), tol);
379         assertEquals(totalStats.getPercentile(50), aggregate.getPercentile(50), tol);
380         assertEquals(totalStats.getPercentile(75), aggregate.getPercentile(75), tol);
381         assertEquals(totalStats.getPercentile(90), aggregate.getPercentile(90), tol);
382         assertEquals(totalStats.getPercentile(99), aggregate.getPercentile(99), tol);
383     }
384 
385     @Test
386     void testAggregateDegenerate() {
387         double[] totalSample = {1, 2, 3, 4, 5};
388         double[][] subSamples = {{1}, {2}, {3}, {4}, {5}};
389 
390         // Compute combined stats directly
391         StreamingStatistics totalStats = new StreamingStatistics();
392         for (int i = 0; i < totalSample.length; i++) {
393             totalStats.addValue(totalSample[i]);
394         }
395 
396         // Now compute subsample stats individually and aggregate
397         StreamingStatistics[] subSampleStats = new StreamingStatistics[5];
398         for (int i = 0; i < 5; i++) {
399             subSampleStats[i] = new StreamingStatistics();
400         }
401         for (int i = 0; i < 5; i++) {
402             for (int j = 0; j < subSamples[i].length; j++) {
403                 subSampleStats[i].addValue(subSamples[i][j]);
404             }
405         }
406 
407         // Compare values
408         StreamingStatistics aggregatedStats = new StreamingStatistics();
409         aggregatedStats.aggregate(subSampleStats);
410 
411         customAssertSummaryStatisticsEquals(totalStats, aggregatedStats, 10e-10);
412     }
413 
414     @Test
415     void testAggregateSpecialValues() {
416         double[] totalSample = {Double.POSITIVE_INFINITY, 2, 3, Double.NaN, 5};
417         double[][] subSamples = {{Double.POSITIVE_INFINITY, 2}, {3}, {Double.NaN}, {5}};
418 
419         // Compute combined stats directly
420         StreamingStatistics totalStats = new StreamingStatistics();
421         for (int i = 0; i < totalSample.length; i++) {
422             totalStats.addValue(totalSample[i]);
423         }
424 
425         // Now compute subsample stats individually and aggregate
426         StreamingStatistics[] subSampleStats = new StreamingStatistics[4];
427         for (int i = 0; i < 4; i++) {
428             subSampleStats[i] = new StreamingStatistics();
429         }
430         for (int i = 0; i < 4; i++) {
431             for (int j = 0; j < subSamples[i].length; j++) {
432                 subSampleStats[i].addValue(subSamples[i][j]);
433             }
434         }
435 
436         // Compare values
437         StreamingStatistics aggregatedStats = new StreamingStatistics();
438         aggregatedStats.aggregate(subSampleStats);
439 
440         customAssertSummaryStatisticsEquals(totalStats, aggregatedStats, 10e-10);
441     }
442 
443     @Test
444     void testBuilderDefault() {
445        StreamingStatistics stats = StreamingStatistics.builder().build();
446        stats.addValue(10);
447        stats.addValue(20);
448        stats.addValue(30);
449        // Percentiles should be NaN, all others should have values
450        assertFalse(Double.isNaN(stats.getMax()));
451        assertFalse(Double.isNaN(stats.getMin()));
452        assertFalse(Double.isNaN(stats.getMean()));
453        assertFalse(Double.isNaN(stats.getSum()));
454        assertFalse(Double.isNaN(stats.getVariance()));
455        assertFalse(Double.isNaN(stats.getPopulationVariance()));
456        assertFalse(Double.isNaN(stats.getStandardDeviation()));
457        assertFalse(Double.isNaN(stats.getGeometricMean()));
458        assertFalse(Double.isNaN(stats.getQuadraticMean()));
459        assertFalse(Double.isNaN(stats.getSumOfSquares()));
460        assertFalse(Double.isNaN(stats.getSumOfLogs()));
461        assertTrue(Double.isNaN(stats.getMedian()));
462        assertTrue(Double.isNaN(stats.getPercentile(10)));
463     }
464 
465     @Test
466     void testBuilderPercentilesOn() {
467         StreamingStatistics stats = StreamingStatistics.
468                 builder().
469                 percentiles(1.0e-6, new Well19937a(0x9b1fadc49a76102al)).
470                 build();
471         stats.addValue(10);
472         stats.addValue(20);
473         stats.addValue(30);
474         assertFalse(Double.isNaN(stats.getMax()));
475         assertFalse(Double.isNaN(stats.getMin()));
476         assertFalse(Double.isNaN(stats.getMean()));
477         assertFalse(Double.isNaN(stats.getSum()));
478         assertFalse(Double.isNaN(stats.getVariance()));
479         assertFalse(Double.isNaN(stats.getPopulationVariance()));
480         assertFalse(Double.isNaN(stats.getStandardDeviation()));
481         assertFalse(Double.isNaN(stats.getGeometricMean()));
482         assertFalse(Double.isNaN(stats.getQuadraticMean()));
483         assertFalse(Double.isNaN(stats.getSumOfSquares()));
484         assertFalse(Double.isNaN(stats.getSumOfLogs()));
485         assertFalse(Double.isNaN(stats.getMedian()));
486         assertFalse(Double.isNaN(stats.getPercentile(10)));
487         stats.clear();
488         assertTrue(Double.isNaN(stats.getMax()));
489         assertTrue(Double.isNaN(stats.getMin()));
490         assertTrue(Double.isNaN(stats.getMean()));
491         assertEquals(0.0, stats.getSum(), 1.0e-15);
492         assertTrue(Double.isNaN(stats.getVariance()));
493         assertTrue(Double.isNaN(stats.getPopulationVariance()));
494         assertTrue(Double.isNaN(stats.getStandardDeviation()));
495         assertTrue(Double.isNaN(stats.getGeometricMean()));
496         assertTrue(Double.isNaN(stats.getQuadraticMean()));
497         assertEquals(0.0, stats.getSumOfSquares(), 1.0e-15);
498         assertEquals(0.0, stats.getSumOfLogs(), 1.0e-15);
499         assertTrue(Double.isNaN(stats.getMedian()));
500         assertTrue(Double.isNaN(stats.getPercentile(10)));
501         assertTrue(Double.isNaN(stats.getPercentile(10)));
502     }
503 
504     @Test
505     void testBuilderMomentsOff() {
506         StreamingStatistics stats = StreamingStatistics.
507                 builder().
508                 percentiles(1.0e-6, new Well19937a(0x9b1fadc49a76102al)).
509                 moments(false).
510                 build();
511         stats.addValue(10);
512         stats.addValue(20);
513         stats.addValue(30);
514         assertFalse(Double.isNaN(stats.getMax()));
515         assertFalse(Double.isNaN(stats.getMin()));
516         assertTrue(Double.isNaN(stats.getMean()));
517         assertTrue(Double.isNaN(stats.getSum()));
518         assertTrue(Double.isNaN(stats.getVariance()));
519         assertTrue(Double.isNaN(stats.getPopulationVariance()));
520         assertTrue(Double.isNaN(stats.getStandardDeviation()));
521         assertFalse(Double.isNaN(stats.getGeometricMean()));
522         assertFalse(Double.isNaN(stats.getQuadraticMean()));
523         assertFalse(Double.isNaN(stats.getSumOfSquares()));
524         assertFalse(Double.isNaN(stats.getSumOfLogs()));
525         assertFalse(Double.isNaN(stats.getMedian()));
526         assertFalse(Double.isNaN(stats.getPercentile(10)));
527         stats.clear();
528         assertTrue(Double.isNaN(stats.getMax()));
529         assertTrue(Double.isNaN(stats.getMin()));
530         assertTrue(Double.isNaN(stats.getMean()));
531         assertTrue(Double.isNaN(stats.getSum()));
532         assertTrue(Double.isNaN(stats.getVariance()));
533         assertTrue(Double.isNaN(stats.getPopulationVariance()));
534         assertTrue(Double.isNaN(stats.getStandardDeviation()));
535         assertTrue(Double.isNaN(stats.getGeometricMean()));
536         assertTrue(Double.isNaN(stats.getQuadraticMean()));
537         assertEquals(0.0, stats.getSumOfSquares(), 1.0e-15);
538         assertEquals(0.0, stats.getSumOfLogs(), 1.0e-15);
539         assertTrue(Double.isNaN(stats.getMedian()));
540         assertTrue(Double.isNaN(stats.getPercentile(10)));
541         assertTrue(Double.isNaN(stats.getPercentile(10)));
542     }
543 
544     @Test
545     void testBuilderSumOfLogsOff() {
546         StreamingStatistics stats = StreamingStatistics.
547                 builder().
548                 percentiles(1.0e-6, new Well19937a(0x9b1fadc49a76102al)).
549                 sumOfLogs(false).
550                 build();
551         stats.addValue(10);
552         stats.addValue(20);
553         stats.addValue(30);
554         assertFalse(Double.isNaN(stats.getMax()));
555         assertFalse(Double.isNaN(stats.getMin()));
556         assertFalse(Double.isNaN(stats.getMean()));
557         assertFalse(Double.isNaN(stats.getSum()));
558         assertFalse(Double.isNaN(stats.getVariance()));
559         assertFalse(Double.isNaN(stats.getPopulationVariance()));
560         assertFalse(Double.isNaN(stats.getStandardDeviation()));
561         assertTrue(Double.isNaN(stats.getGeometricMean()));
562         assertFalse(Double.isNaN(stats.getQuadraticMean()));
563         assertFalse(Double.isNaN(stats.getSumOfSquares()));
564         assertTrue(Double.isNaN(stats.getSumOfLogs()));
565         assertFalse(Double.isNaN(stats.getMedian()));
566         assertFalse(Double.isNaN(stats.getPercentile(10)));
567         stats.clear();
568         assertTrue(Double.isNaN(stats.getMax()));
569         assertTrue(Double.isNaN(stats.getMin()));
570         assertTrue(Double.isNaN(stats.getMean()));
571         assertEquals(0.0, stats.getSum(), 1.0e-15);
572         assertTrue(Double.isNaN(stats.getVariance()));
573         assertTrue(Double.isNaN(stats.getPopulationVariance()));
574         assertTrue(Double.isNaN(stats.getStandardDeviation()));
575         assertTrue(Double.isNaN(stats.getGeometricMean()));
576         assertTrue(Double.isNaN(stats.getQuadraticMean()));
577         assertEquals(0.0, stats.getSumOfSquares(), 1.0e-15);
578         assertTrue(Double.isNaN(stats.getSumOfLogs()));
579         assertTrue(Double.isNaN(stats.getMedian()));
580         assertTrue(Double.isNaN(stats.getPercentile(10)));
581         assertTrue(Double.isNaN(stats.getPercentile(10)));
582     }
583 
584     @Test
585     void testBuilderExtremaOff() {
586         StreamingStatistics stats = StreamingStatistics.
587                 builder().
588                 percentiles(1.0e-6, new Well19937a(0x9b1fadc49a76102al)).
589                 extrema(false).
590                 build();
591         stats.addValue(10);
592         stats.addValue(20);
593         stats.addValue(30);
594         assertTrue(Double.isNaN(stats.getMax()));
595         assertTrue(Double.isNaN(stats.getMin()));
596         assertFalse(Double.isNaN(stats.getMean()));
597         assertFalse(Double.isNaN(stats.getSum()));
598         assertFalse(Double.isNaN(stats.getVariance()));
599         assertFalse(Double.isNaN(stats.getPopulationVariance()));
600         assertFalse(Double.isNaN(stats.getStandardDeviation()));
601         assertFalse(Double.isNaN(stats.getGeometricMean()));
602         assertFalse(Double.isNaN(stats.getQuadraticMean()));
603         assertFalse(Double.isNaN(stats.getSumOfSquares()));
604         assertFalse(Double.isNaN(stats.getSumOfLogs()));
605         assertFalse(Double.isNaN(stats.getMedian()));
606         assertFalse(Double.isNaN(stats.getPercentile(10)));
607         stats.clear();
608         assertTrue(Double.isNaN(stats.getMax()));
609         assertTrue(Double.isNaN(stats.getMin()));
610         assertTrue(Double.isNaN(stats.getMean()));
611         assertEquals(0.0, stats.getSum(), 1.0e-15);
612         assertTrue(Double.isNaN(stats.getVariance()));
613         assertTrue(Double.isNaN(stats.getPopulationVariance()));
614         assertTrue(Double.isNaN(stats.getStandardDeviation()));
615         assertTrue(Double.isNaN(stats.getGeometricMean()));
616         assertTrue(Double.isNaN(stats.getQuadraticMean()));
617         assertEquals(0.0, stats.getSumOfSquares(), 1.0e-15);
618         assertEquals(0.0, stats.getSumOfLogs(), 1.0e-15);
619         assertTrue(Double.isNaN(stats.getMedian()));
620         assertTrue(Double.isNaN(stats.getPercentile(10)));
621         assertTrue(Double.isNaN(stats.getPercentile(10)));
622     }
623 
624     @Test
625     void testBuilderSumOfSquares() {
626         StreamingStatistics stats = StreamingStatistics.
627                 builder().
628                 percentiles(1.0e-6, new Well19937a(0x9b1fadc49a76102al)).
629                 sumOfSquares(false).
630                 build();
631         stats.addValue(10);
632         stats.addValue(20);
633         stats.addValue(30);
634         assertFalse(Double.isNaN(stats.getMax()));
635         assertFalse(Double.isNaN(stats.getMin()));
636         assertFalse(Double.isNaN(stats.getMean()));
637         assertFalse(Double.isNaN(stats.getSum()));
638         assertFalse(Double.isNaN(stats.getVariance()));
639         assertFalse(Double.isNaN(stats.getPopulationVariance()));
640         assertFalse(Double.isNaN(stats.getStandardDeviation()));
641         assertFalse(Double.isNaN(stats.getGeometricMean()));
642         assertTrue(Double.isNaN(stats.getQuadraticMean()));
643         assertTrue(Double.isNaN(stats.getSumOfSquares()));
644         assertFalse(Double.isNaN(stats.getSumOfLogs()));
645         assertFalse(Double.isNaN(stats.getMedian()));
646         assertFalse(Double.isNaN(stats.getPercentile(10)));
647         stats.clear();
648         assertTrue(Double.isNaN(stats.getMax()));
649         assertTrue(Double.isNaN(stats.getMin()));
650         assertTrue(Double.isNaN(stats.getMean()));
651         assertEquals(0.0, stats.getSum(), 1.0e-15);
652         assertTrue(Double.isNaN(stats.getVariance()));
653         assertTrue(Double.isNaN(stats.getPopulationVariance()));
654         assertTrue(Double.isNaN(stats.getStandardDeviation()));
655         assertTrue(Double.isNaN(stats.getGeometricMean()));
656         assertTrue(Double.isNaN(stats.getQuadraticMean()));
657         assertTrue(Double.isNaN(stats.getSumOfSquares()));
658         assertEquals(0.0, stats.getSumOfLogs(), 1.0e-15);
659         assertTrue(Double.isNaN(stats.getMedian()));
660         assertTrue(Double.isNaN(stats.getPercentile(10)));
661         assertTrue(Double.isNaN(stats.getPercentile(10)));
662     }
663 
664     /**
665      * Verifies that a StatisticalSummary and a StatisticalSummaryValues are equal up
666      * to delta, with NaNs, infinities returned in the same spots. For max, min, n, values
667      * have to agree exactly, delta is used only for sum, mean, variance, std dev.
668      */
669     protected static void customAssertSummaryStatisticsEquals(StreamingStatistics expected,
670                                                               StreamingStatistics observed,
671                                                               double delta) {
672         UnitTestUtils.customAssertEquals(expected.getMax(), observed.getMax(), 0);
673         UnitTestUtils.customAssertEquals(expected.getMin(), observed.getMin(), 0);
674         assertEquals(expected.getN(), observed.getN());
675         UnitTestUtils.customAssertEquals(expected.getSum(), observed.getSum(), delta);
676         UnitTestUtils.customAssertEquals(expected.getMean(), observed.getMean(), delta);
677         UnitTestUtils.customAssertEquals(expected.getStandardDeviation(), observed.getStandardDeviation(), delta);
678         UnitTestUtils.customAssertEquals(expected.getVariance(), observed.getVariance(), delta);
679     }
680 
681 
682     /**
683      * Generates a random sample of double values.
684      * Sample size is random, between 10 and 100 and values are
685      * uniformly distributed over [-100, 100].
686      *
687      * @return array of random double values
688      */
689     private double[] generateSample() {
690         final RealDistribution uniformDist = new UniformRealDistribution(-100, 100);
691         final RandomDataGenerator randomDataGenerator = new RandomDataGenerator(100);
692         final int sampleSize = randomDataGenerator.nextInt(10, 100);
693         final double[] out = randomDataGenerator.nextDeviates(uniformDist, sampleSize);
694         return out;
695     }
696 
697     /**
698      * Generates a partition of <sample> into up to 5 sequentially selected
699      * subsamples with randomly selected partition points.
700      *
701      * @param sample array to partition
702      * @return rectangular array with rows = subsamples
703      */
704     private double[][] generatePartition(double[] sample) {
705         final int length = sample.length;
706         final double[][] out = new double[5][];
707         final RandomDataGenerator randomDataGenerator = new RandomDataGenerator(100);
708         int cur = 0;          // beginning of current partition segment
709         int offset = 0;       // end of current partition segment
710         int sampleCount = 0;  // number of segments defined
711         for (int i = 0; i < 5; i++) {
712             if (cur == length || offset == length) {
713                 break;
714             }
715             final int next;
716             if (i == 4 || cur == length - 1) {
717                 next = length - 1;
718             } else {
719                 next = randomDataGenerator.nextInt(cur, length - 1);
720             }
721             final int subLength = next - cur + 1;
722             out[i] = new double[subLength];
723             System.arraycopy(sample, offset, out[i], 0, subLength);
724             cur = next + 1;
725             sampleCount++;
726             offset += subLength;
727         }
728         if (sampleCount < 5) {
729             double[][] out2 = new double[sampleCount][];
730             for (int j = 0; j < sampleCount; j++) {
731                 final int curSize = out[j].length;
732                 out2[j] = new double[curSize];
733                 System.arraycopy(out[j], 0, out2[j], 0, curSize);
734             }
735             return out2;
736         } else {
737             return out;
738         }
739     }
740 
741 }