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    *      http://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  package org.apache.commons.math4.legacy.stat.descriptive;
18  
19  
20  import org.apache.commons.math4.legacy.TestUtils;
21  import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
22  import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean;
23  import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean;
24  import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance;
25  import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum;
26  import org.apache.commons.math4.core.jdkmath.JdkMath;
27  import org.junit.Assert;
28  import org.junit.Test;
29  /**
30   * Test cases for the {@link SummaryStatistics} class.
31   */
32  public class SummaryStatisticsTest {
33  
34      private final double one = 1;
35      private final float twoF = 2;
36      private final long twoL = 2;
37      private final int three = 3;
38      private final double mean = 2;
39      private final double sumSq = 18;
40      private final double sum = 8;
41      private final double var = 0.666666666666666666667;
42      private final double popVar = 0.5;
43      private final double std = JdkMath.sqrt(var);
44      private final double n = 4;
45      private final double min = 1;
46      private final double max = 3;
47      private final double tolerance = 10E-15;
48  
49      protected SummaryStatistics createSummaryStatistics() {
50          return new SummaryStatistics();
51      }
52  
53      /** test stats */
54      @Test
55      public void testStats() {
56          SummaryStatistics u = createSummaryStatistics();
57          Assert.assertEquals("total count",0,u.getN(),tolerance);
58          u.addValue(one);
59          u.addValue(twoF);
60          u.addValue(twoL);
61          u.addValue(three);
62          Assert.assertEquals("N",n,u.getN(),tolerance);
63          Assert.assertEquals("sum",sum,u.getSum(),tolerance);
64          Assert.assertEquals("sumsq",sumSq,u.getSumsq(),tolerance);
65          Assert.assertEquals("var",var,u.getVariance(),tolerance);
66          Assert.assertEquals("population var",popVar,u.getPopulationVariance(),tolerance);
67          Assert.assertEquals("std",std,u.getStandardDeviation(),tolerance);
68          Assert.assertEquals("mean",mean,u.getMean(),tolerance);
69          Assert.assertEquals("min",min,u.getMin(),tolerance);
70          Assert.assertEquals("max",max,u.getMax(),tolerance);
71          u.clear();
72          Assert.assertEquals("total count",0,u.getN(),tolerance);
73      }
74  
75      @Test
76      public void testN0andN1Conditions() {
77          SummaryStatistics u = createSummaryStatistics();
78          Assert.assertTrue("Mean of n = 0 set should be NaN",
79                  Double.isNaN( u.getMean() ) );
80          Assert.assertTrue("Standard Deviation of n = 0 set should be NaN",
81                  Double.isNaN( u.getStandardDeviation() ) );
82          Assert.assertTrue("Variance of n = 0 set should be NaN",
83                  Double.isNaN(u.getVariance() ) );
84  
85          /* n=1 */
86          u.addValue(one);
87          Assert.assertEquals("mean should be one (n = 1)", one, u.getMean(), 0.0);
88          Assert.assertEquals("geometric should be one (n = 1) instead it is " + u.getGeometricMean(), one, u.getGeometricMean(), 0.0);
89          Assert.assertEquals("Std should be zero (n = 1)", 0.0, u.getStandardDeviation(), 0.0);
90          Assert.assertEquals("variance should be zero (n = 1)", 0.0, u.getVariance(), 0.0);
91  
92          /* n=2 */
93          u.addValue(twoF);
94          Assert.assertTrue("Std should not be zero (n = 2)",
95                  u.getStandardDeviation() != 0.0);
96          Assert.assertTrue("variance should not be zero (n = 2)",
97                  u.getVariance() != 0.0);
98      }
99  
100     @Test
101     public void testProductAndGeometricMean() {
102         SummaryStatistics u = createSummaryStatistics();
103         u.addValue( 1.0 );
104         u.addValue( 2.0 );
105         u.addValue( 3.0 );
106         u.addValue( 4.0 );
107 
108         Assert.assertEquals( "Geometric mean not expected", 2.213364,
109                 u.getGeometricMean(), 0.00001 );
110     }
111 
112     @Test
113     public void testNaNContracts() {
114         SummaryStatistics u = createSummaryStatistics();
115         Assert.assertTrue("mean not NaN",Double.isNaN(u.getMean()));
116         Assert.assertTrue("min not NaN",Double.isNaN(u.getMin()));
117         Assert.assertTrue("std dev not NaN",Double.isNaN(u.getStandardDeviation()));
118         Assert.assertTrue("var not NaN",Double.isNaN(u.getVariance()));
119         Assert.assertTrue("geom mean not NaN",Double.isNaN(u.getGeometricMean()));
120 
121         u.addValue(1.0);
122 
123         Assert.assertEquals( "mean not expected", 1.0,
124                 u.getMean(), Double.MIN_VALUE);
125         Assert.assertEquals( "variance not expected", 0.0,
126                 u.getVariance(), Double.MIN_VALUE);
127         Assert.assertEquals( "geometric mean not expected", 1.0,
128                 u.getGeometricMean(), Double.MIN_VALUE);
129 
130         u.addValue(-1.0);
131 
132         Assert.assertTrue("geom mean not NaN",Double.isNaN(u.getGeometricMean()));
133 
134         u.addValue(0.0);
135 
136         Assert.assertTrue("geom mean not NaN",Double.isNaN(u.getGeometricMean()));
137 
138         //FiXME: test all other NaN contract specs
139     }
140 
141     @Test
142     public void testGetSummary() {
143         SummaryStatistics u = createSummaryStatistics();
144         StatisticalSummary summary = u.getSummary();
145         verifySummary(u, summary);
146         u.addValue(1d);
147         summary = u.getSummary();
148         verifySummary(u, summary);
149         u.addValue(2d);
150         summary = u.getSummary();
151         verifySummary(u, summary);
152         u.addValue(2d);
153         summary = u.getSummary();
154         verifySummary(u, summary);
155     }
156 
157     @Test
158     public void testEqualsAndHashCode() {
159         SummaryStatistics u = createSummaryStatistics();
160         SummaryStatistics t = null;
161         int emptyHash = u.hashCode();
162         Assert.assertEquals("reflexive", u, u);
163         Assert.assertNotEquals("non-null compared to null", u, t);
164         Assert.assertFalse("wrong type", u.equals(Double.valueOf(0)));
165         t = createSummaryStatistics();
166         Assert.assertEquals("empty instances should be equal", t, u);
167         Assert.assertEquals("empty instances should be equal", u, t);
168         Assert.assertEquals("empty hash code", emptyHash, t.hashCode());
169 
170         // Add some data to u
171         u.addValue(2d);
172         u.addValue(1d);
173         u.addValue(3d);
174         u.addValue(4d);
175         Assert.assertNotEquals("different n's should make instances not equal", t, u);
176         Assert.assertNotEquals("different n's should make instances not equal", u, t);
177         Assert.assertTrue("different n's should make hash codes different",
178                 u.hashCode() != t.hashCode());
179 
180         //Add data in same order to t
181         t.addValue(2d);
182         t.addValue(1d);
183         t.addValue(3d);
184         t.addValue(4d);
185         Assert.assertEquals("summaries based on same data should be equal", t, u);
186         Assert.assertEquals("summaries based on same data should be equal", u, t);
187         Assert.assertEquals("summaries based on same data should have same hash codes",
188                 u.hashCode(), t.hashCode());
189 
190         // Clear and make sure summaries are indistinguishable from empty summary
191         u.clear();
192         t.clear();
193         Assert.assertEquals("empty instances should be equal", t, u);
194         Assert.assertEquals("empty instances should be equal", u, t);
195         Assert.assertEquals("empty hash code", emptyHash, t.hashCode());
196         Assert.assertEquals("empty hash code", emptyHash, u.hashCode());
197     }
198 
199     @Test
200     public void testCopy() {
201         SummaryStatistics u = createSummaryStatistics();
202         u.addValue(2d);
203         u.addValue(1d);
204         u.addValue(3d);
205         u.addValue(4d);
206         SummaryStatistics v = new SummaryStatistics(u);
207         Assert.assertEquals(u, v);
208         Assert.assertEquals(v, u);
209 
210         // Make sure both behave the same with additional values added
211         u.addValue(7d);
212         u.addValue(9d);
213         u.addValue(11d);
214         u.addValue(23d);
215         v.addValue(7d);
216         v.addValue(9d);
217         v.addValue(11d);
218         v.addValue(23d);
219         Assert.assertEquals(u, v);
220         Assert.assertEquals(v, u);
221 
222         // Check implementation pointers are preserved
223         u.clear();
224         u.setSumImpl(new Sum());
225         SummaryStatistics.copy(u,v);
226         Assert.assertEquals(u.getSumImpl(), v.getSumImpl());
227     }
228 
229     private void verifySummary(SummaryStatistics u, StatisticalSummary s) {
230         Assert.assertEquals("N",s.getN(),u.getN());
231         TestUtils.assertEquals("sum",s.getSum(),u.getSum(),tolerance);
232         TestUtils.assertEquals("var",s.getVariance(),u.getVariance(),tolerance);
233         TestUtils.assertEquals("std",s.getStandardDeviation(),u.getStandardDeviation(),tolerance);
234         TestUtils.assertEquals("mean",s.getMean(),u.getMean(),tolerance);
235         TestUtils.assertEquals("min",s.getMin(),u.getMin(),tolerance);
236         TestUtils.assertEquals("max",s.getMax(),u.getMax(),tolerance);
237     }
238 
239     @Test
240     public void testSetterInjection() {
241         SummaryStatistics u = createSummaryStatistics();
242         u.setMeanImpl(new Sum());
243         u.setSumLogImpl(new Sum());
244         u.addValue(1);
245         u.addValue(3);
246         Assert.assertEquals(4, u.getMean(), 1E-14);
247         Assert.assertEquals(4, u.getSumOfLogs(), 1E-14);
248         Assert.assertEquals(JdkMath.exp(2), u.getGeometricMean(), 1E-14);
249         u.clear();
250         u.addValue(1);
251         u.addValue(2);
252         Assert.assertEquals(3, u.getMean(), 1E-14);
253         u.clear();
254         u.setMeanImpl(new Mean()); // OK after clear
255     }
256 
257     @Test
258     public void testSetterIllegalState() {
259         SummaryStatistics u = createSummaryStatistics();
260         u.addValue(1);
261         u.addValue(3);
262         try {
263             u.setMeanImpl(new Sum());
264             Assert.fail("Expecting MathIllegalStateException");
265         } catch (MathIllegalStateException ex) {
266             // expected
267         }
268     }
269 
270     @Test
271     public void testQuadraticMean() {
272         final double[] values = { 1.2, 3.4, 5.6, 7.89 };
273         final SummaryStatistics stats = createSummaryStatistics();
274 
275         final int len = values.length;
276         double expected = 0;
277         for (int i = 0; i < len; i++) {
278             final double v = values[i];
279             expected += v * v / len;
280 
281             stats.addValue(v);
282         }
283         expected = Math.sqrt(expected);
284 
285         Assert.assertEquals(expected, stats.getQuadraticMean(), Math.ulp(expected));
286     }
287 
288     /**
289      * JIRA: MATH-691
290      */
291     @Test
292     public void testOverrideVarianceWithMathClass() {
293         double[] scores = {1, 2, 3, 4};
294         SummaryStatistics stats = new SummaryStatistics();
295         stats.setVarianceImpl(new Variance(false)); //use "population variance"
296         for(double i : scores) {
297           stats.addValue(i);
298         }
299         Assert.assertEquals((new Variance(false)).evaluate(scores),stats.getVariance(), 0);
300     }
301 
302     @Test
303     public void testOverrideMeanWithMathClass() {
304         double[] scores = {1, 2, 3, 4};
305         SummaryStatistics stats = new SummaryStatistics();
306         stats.setMeanImpl(new Mean());
307         for(double i : scores) {
308           stats.addValue(i);
309         }
310         Assert.assertEquals((new Mean()).evaluate(scores),stats.getMean(), 0);
311     }
312 
313     @Test
314     public void testOverrideGeoMeanWithMathClass() {
315         double[] scores = {1, 2, 3, 4};
316         SummaryStatistics stats = new SummaryStatistics();
317         stats.setGeoMeanImpl(new GeometricMean());
318         for(double i : scores) {
319           stats.addValue(i);
320         }
321         Assert.assertEquals((new GeometricMean()).evaluate(scores),stats.getGeometricMean(), 0);
322     }
323 
324     @Test
325     public void testToString() {
326         SummaryStatistics u = createSummaryStatistics();
327         for (int i = 0; i < 5; i++) {
328             u.addValue(i);
329         }
330         final String[] labels = {"min", "max", "sum", "geometric mean", "variance",
331                 "population variance", "second moment", "sum of squares", "standard deviation",
332         "sum of logs"};
333         final double[] values = {u.getMin(), u.getMax(), u.getSum(), u.getGeometricMean(),
334                 u.getVariance(), u.getPopulationVariance(), u.getSecondMoment(), u.getSumsq(),
335                 u.getStandardDeviation(), u.getSumOfLogs()};
336         final String toString = u.toString();
337         Assert.assertTrue(toString.indexOf("n: " + u.getN()) > 0); // getN() returns a long
338         for (int i = 0; i < values.length; i++) {
339             Assert.assertTrue(toString.indexOf(labels[i] + ": " + String.valueOf(values[i])) > 0);
340         }
341     }
342 }