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