1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to You under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
9    * or agreed to in writing, software distributed under the License is
10   * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11   * KIND, either express or implied. See the License for the specific language
12   * governing permissions and limitations under the License.
13   */
14  package org.apache.commons.math.stat.descriptive;
15  
16  import java.util.Locale;
17  
18  import junit.framework.Test;
19  import junit.framework.TestCase;
20  import junit.framework.TestSuite;
21  
22  import org.apache.commons.math.stat.descriptive.rank.Percentile;
23  import org.apache.commons.math.util.MathUtils;
24  
25  /**
26   * Test cases for the DescriptiveStatistics class.
27   * 
28   * @version $Revision: 797742 $ $Date: 2007-08-16 15:36:33 -0500 (Thu, 16 Aug
29   *          2007) $
30   */
31  public class DescriptiveStatisticsTest extends TestCase {
32  
33      public DescriptiveStatisticsTest(String name) {
34          super(name);
35      }
36  
37      public static Test suite() {
38          TestSuite suite = new TestSuite(DescriptiveStatisticsTest.class);
39          suite.setName("DescriptiveStatistics Tests");
40          return suite;
41      }
42  
43      protected DescriptiveStatistics createDescriptiveStatistics() {
44          return new DescriptiveStatistics();
45      }
46  
47      public void testSetterInjection() {
48          DescriptiveStatistics stats = createDescriptiveStatistics();
49          stats.addValue(1);
50          stats.addValue(3);
51          assertEquals(2, stats.getMean(), 1E-10);
52          // Now lets try some new math
53          stats.setMeanImpl(new deepMean());
54          assertEquals(42, stats.getMean(), 1E-10);
55      }
56      
57      public void testCopy() {
58          DescriptiveStatistics stats = createDescriptiveStatistics();
59          stats.addValue(1);
60          stats.addValue(3);
61          DescriptiveStatistics copy = new DescriptiveStatistics(stats);
62          assertEquals(2, copy.getMean(), 1E-10);
63          // Now lets try some new math
64          stats.setMeanImpl(new deepMean());
65          copy = stats.copy();
66          assertEquals(42, copy.getMean(), 1E-10);
67      }
68      
69      public void testWindowSize() {
70          DescriptiveStatistics stats = createDescriptiveStatistics();
71          stats.setWindowSize(300);
72          for (int i = 0; i < 100; ++i) {
73              stats.addValue(i + 1);
74          }
75          int refSum = (100 * 101) / 2;
76          assertEquals(refSum / 100.0, stats.getMean(), 1E-10);
77          assertEquals(300, stats.getWindowSize());
78          try {
79              stats.setWindowSize(-3);
80              fail("an exception should have been thrown");
81          } catch (IllegalArgumentException iae) {
82              // expected
83          } catch (Exception e) {
84              fail("wrong exception caught: " + e.getMessage());
85          }
86          assertEquals(300, stats.getWindowSize());
87          stats.setWindowSize(50);
88          assertEquals(50, stats.getWindowSize());
89          int refSum2 = refSum - (50 * 51) / 2;
90          assertEquals(refSum2 / 50.0, stats.getMean(), 1E-10);
91      }
92      
93      public void testGetValues() {
94          DescriptiveStatistics stats = createDescriptiveStatistics();
95          for (int i = 100; i > 0; --i) {
96              stats.addValue(i);
97          }
98          int refSum = (100 * 101) / 2;
99          assertEquals(refSum / 100.0, stats.getMean(), 1E-10);
100         double[] v = stats.getValues();
101         for (int i = 0; i < v.length; ++i) {
102             assertEquals(100.0 - i, v[i], 1.0e-10);
103         }
104         double[] s = stats.getSortedValues();
105         for (int i = 0; i < s.length; ++i) {
106             assertEquals(i + 1.0, s[i], 1.0e-10);
107         }
108         assertEquals(12.0, stats.getElement(88), 1.0e-10);
109     }
110     
111     public void testToString() {
112         DescriptiveStatistics stats = createDescriptiveStatistics();
113         stats.addValue(1);
114         stats.addValue(2);
115         stats.addValue(3);
116         Locale d = Locale.getDefault();
117         Locale.setDefault(Locale.US);
118         assertEquals("DescriptiveStatistics:\n" +
119                      "n: 3\n" +
120                      "min: 1.0\n" +
121                      "max: 3.0\n" +
122                      "mean: 2.0\n" +
123                      "std dev: 1.0\n" +
124                      "median: 2.0\n" +
125                      "skewness: 0.0\n" +
126                      "kurtosis: NaN\n",  stats.toString());
127         Locale.setDefault(d);
128     }
129 
130     public void testShuffledStatistics() {
131         // the purpose of this test is only to check the get/set methods
132         // we are aware shuffling statistics like this is really not
133         // something sensible to do in production ...
134         DescriptiveStatistics reference = createDescriptiveStatistics();
135         DescriptiveStatistics shuffled  = createDescriptiveStatistics();
136 
137         UnivariateStatistic tmp = shuffled.getGeometricMeanImpl();
138         shuffled.setGeometricMeanImpl(shuffled.getMeanImpl());
139         shuffled.setMeanImpl(shuffled.getKurtosisImpl());
140         shuffled.setKurtosisImpl(shuffled.getSkewnessImpl());
141         shuffled.setSkewnessImpl(shuffled.getVarianceImpl());
142         shuffled.setVarianceImpl(shuffled.getMaxImpl());
143         shuffled.setMaxImpl(shuffled.getMinImpl());
144         shuffled.setMinImpl(shuffled.getSumImpl());
145         shuffled.setSumImpl(shuffled.getSumsqImpl());
146         shuffled.setSumsqImpl(tmp);
147 
148         for (int i = 100; i > 0; --i) {
149             reference.addValue(i);
150             shuffled.addValue(i);
151         }
152 
153         assertEquals(reference.getMean(),          shuffled.getGeometricMean(), 1.0e-10);
154         assertEquals(reference.getKurtosis(),      shuffled.getMean(),          1.0e-10);
155         assertEquals(reference.getSkewness(),      shuffled.getKurtosis(), 1.0e-10);
156         assertEquals(reference.getVariance(),      shuffled.getSkewness(), 1.0e-10);
157         assertEquals(reference.getMax(),           shuffled.getVariance(), 1.0e-10);
158         assertEquals(reference.getMin(),           shuffled.getMax(), 1.0e-10);
159         assertEquals(reference.getSum(),           shuffled.getMin(), 1.0e-10);
160         assertEquals(reference.getSumsq(),         shuffled.getSum(), 1.0e-10);
161         assertEquals(reference.getGeometricMean(), shuffled.getSumsq(), 1.0e-10);
162 
163     }
164     
165     public void testPercentileSetter() throws Exception {
166         DescriptiveStatistics stats = createDescriptiveStatistics();
167         stats.addValue(1);
168         stats.addValue(2);
169         stats.addValue(3);
170         assertEquals(2, stats.getPercentile(50.0), 1E-10);
171         
172         // Inject wrapped Percentile impl
173         stats.setPercentileImpl(new goodPercentile());
174         assertEquals(2, stats.getPercentile(50.0), 1E-10);
175         
176         // Try "new math" impl
177         stats.setPercentileImpl(new subPercentile());
178         assertEquals(10.0, stats.getPercentile(10.0), 1E-10);
179         
180         // Try to set bad impl
181         try {
182             stats.setPercentileImpl(new badPercentile()); 
183             fail("Expecting IllegalArgumentException");
184         } catch (IllegalArgumentException ex) {
185             // expected
186         }
187     }
188 
189     public void test20090720() {
190         DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics(100);
191         for (int i = 0; i < 161; i++) {
192             descriptiveStatistics.addValue(1.2);
193         }
194         descriptiveStatistics.clear();
195         descriptiveStatistics.addValue(1.2);
196         assertEquals(1, descriptiveStatistics.getN());
197     }
198 
199     public void testRemoval() {
200 
201         final DescriptiveStatistics dstat = createDescriptiveStatistics();
202 
203         checkremoval(dstat, 1, 6.0, 0.0, Double.NaN);
204         checkremoval(dstat, 3, 5.0, 3.0, 4.5);
205         checkremoval(dstat, 6, 3.5, 2.5, 3.0);
206         checkremoval(dstat, 9, 3.5, 2.5, 3.0);
207         checkremoval(dstat, DescriptiveStatistics.INFINITE_WINDOW, 3.5, 2.5, 3.0);
208 
209     }
210 
211     public void checkremoval(DescriptiveStatistics dstat, int wsize,
212                              double mean1, double mean2, double mean3) {
213 
214         dstat.setWindowSize(wsize);
215         dstat.clear();
216 
217         for (int i = 1 ; i <= 6 ; ++i) {
218             dstat.addValue(i);
219         }
220 
221         assertTrue(MathUtils.equals(mean1, dstat.getMean()));
222         dstat.replaceMostRecentValue(0);
223         assertTrue(MathUtils.equals(mean2, dstat.getMean()));
224         dstat.removeMostRecentValue();
225         assertTrue(MathUtils.equals(mean3, dstat.getMean()));
226 
227     }
228     
229     // Test UnivariateStatistics impls for setter injection tests
230     
231     /**
232      * A new way to compute the mean 
233      */
234     static class deepMean implements UnivariateStatistic {
235 
236         public double evaluate(double[] values, int begin, int length) {
237             return 42;
238         }
239 
240         public double evaluate(double[] values) {
241             return 42;
242         }  
243         public UnivariateStatistic copy() {
244             return new deepMean();
245         }
246     }
247     
248     /**
249      * Test percentile implementation - wraps a Percentile
250      */
251     static class goodPercentile implements UnivariateStatistic {
252         private Percentile percentile = new Percentile();
253         public void setQuantile(double quantile) {
254             percentile.setQuantile(quantile);
255         }
256         public double evaluate(double[] values, int begin, int length) {
257             return percentile.evaluate(values, begin, length);
258         }
259         public double evaluate(double[] values) {
260             return percentile.evaluate(values);
261         }  
262         public UnivariateStatistic copy() {
263             goodPercentile result = new goodPercentile();
264             result.setQuantile(percentile.getQuantile());
265             return result;
266         }
267     }
268     
269     /**
270      * Test percentile subclass - another "new math" impl
271      * Always returns currently set quantile
272      */
273     static class subPercentile extends Percentile {
274         @Override
275         public double evaluate(double[] values, int begin, int length) {
276             return getQuantile();
277         }
278         @Override
279         public double evaluate(double[] values) {
280             return getQuantile();
281         }  
282         private static final long serialVersionUID = 8040701391045914979L;
283         @Override
284         public Percentile copy() {
285             subPercentile result = new subPercentile();
286             return result;
287         }
288     }
289     
290     /**
291      * "Bad" test percentile implementation - no setQuantile
292      */
293     static class badPercentile implements UnivariateStatistic {
294         private Percentile percentile = new Percentile();
295         public double evaluate(double[] values, int begin, int length) {
296             return percentile.evaluate(values, begin, length);
297         }
298         public double evaluate(double[] values) {
299             return percentile.evaluate(values);
300         }
301         public UnivariateStatistic copy() {
302             return new badPercentile();
303         }
304     }
305     
306 }