1   /*
2    * Copyright 2003-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.math.stat;
17  
18  import junit.framework.Test;
19  import junit.framework.TestCase;
20  import junit.framework.TestSuite;
21  
22  import org.apache.commons.math.TestUtils;
23  
24  /**
25   * Test cases for the {@link StatUtils} class.
26   * @version $Revision: 348888 $ $Date: 2005-11-24 23:21:25 -0700 (Thu, 24 Nov 2005) $
27   */
28  
29  public final class StatUtilsTest extends TestCase {
30  
31      private double one = 1;
32      private float two = 2;
33      private int three = 3;
34      private double mean = 2;
35      private double sumSq = 18;
36      private double sum = 8;
37      private double var = 0.666666666666666666667;
38      private double std = Math.sqrt(var);
39      private double n = 4;
40      private double min = 1;
41      private double max = 3;
42      private double skewness = 0;
43      private double kurtosis = 0.5;
44      private double tolerance = 10E-15;
45      private double nan = Double.NaN;
46  
47      public StatUtilsTest(String name) {
48          super(name);
49      }
50  
51      public void setUp() {
52      }
53  
54      public static Test suite() {
55          TestSuite suite = new TestSuite(StatUtilsTest.class);
56          suite.setName("StatUtil Tests");
57          return suite;
58      }
59  
60      /** test stats */
61      public void testStats() {
62          double[] values = new double[] { one, two, two, three };
63          assertEquals("sum", sum, StatUtils.sum(values), tolerance);
64          assertEquals("sumsq", sumSq, StatUtils.sumSq(values), tolerance);
65          assertEquals("var", var, StatUtils.variance(values), tolerance);
66          assertEquals("var with mean", var, StatUtils.variance(values, mean), tolerance);
67          assertEquals("mean", mean, StatUtils.mean(values), tolerance);
68          assertEquals("min", min, StatUtils.min(values), tolerance);
69          assertEquals("max", max, StatUtils.max(values), tolerance);
70      }
71  
72      public void testN0andN1Conditions() throws Exception {
73          double[] values = new double[0];
74  
75          assertTrue(
76              "Mean of n = 0 set should be NaN",
77              Double.isNaN(StatUtils.mean(values)));
78          assertTrue(
79              "Variance of n = 0 set should be NaN",
80              Double.isNaN(StatUtils.variance(values)));
81  
82          values = new double[] { one };
83  
84          assertTrue(
85              "Mean of n = 1 set should be value of single item n1",
86              StatUtils.mean(values) == one);
87          assertTrue(
88              "Variance of n = 1 set should be zero",
89              StatUtils.variance(values) == 0);
90      }
91  
92      public void testArrayIndexConditions() throws Exception {
93          double[] values = { 1.0, 2.0, 3.0, 4.0 };
94  
95          assertEquals(
96              "Sum not expected",
97              5.0,
98              StatUtils.sum(values, 1, 2),
99              Double.MIN_VALUE);
100         assertEquals(
101             "Sum not expected",
102             3.0,
103             StatUtils.sum(values, 0, 2),
104             Double.MIN_VALUE);
105         assertEquals(
106             "Sum not expected",
107             7.0,
108             StatUtils.sum(values, 2, 2),
109             Double.MIN_VALUE);
110 
111         try {
112             StatUtils.sum(values, 2, 3);
113             assertTrue("Didn't throw exception", false);
114         } catch (Exception e) {
115             assertTrue(true);
116         }
117 
118         try {
119             StatUtils.sum(values, -1, 2);
120             assertTrue("Didn't throw exception", false);
121         } catch (Exception e) {
122             assertTrue(true);
123         }
124 
125     }
126     
127     public void testSumSq() {
128         double[] x = null;
129         
130         // test null
131         try {
132             StatUtils.sumSq(x);
133             fail("null is not a valid data array.");
134         } catch (IllegalArgumentException ex) {
135             // success
136         }
137         
138         try {
139             StatUtils.sumSq(x, 0, 4);
140             fail("null is not a valid data array.");
141         } catch (IllegalArgumentException ex) {
142             // success
143         }
144         
145         // test empty
146         x = new double[] {};
147         TestUtils.assertEquals(Double.NaN, StatUtils.sumSq(x), tolerance);
148         TestUtils.assertEquals(Double.NaN, StatUtils.sumSq(x, 0, 0), tolerance);
149         
150         // test one
151         x = new double[] {two};
152         TestUtils.assertEquals(4, StatUtils.sumSq(x), tolerance);
153         TestUtils.assertEquals(4, StatUtils.sumSq(x, 0, 1), tolerance);
154         
155         // test many
156         x = new double[] {one, two, two, three};
157         TestUtils.assertEquals(18, StatUtils.sumSq(x), tolerance);
158         TestUtils.assertEquals(8, StatUtils.sumSq(x, 1, 2), tolerance);
159     }
160     
161     public void testProduct() {
162         double[] x = null;
163         
164         // test null
165         try {
166             StatUtils.product(x);
167             fail("null is not a valid data array.");
168         } catch (IllegalArgumentException ex) {
169             // success
170         }
171         
172         try {
173             StatUtils.product(x, 0, 4);
174             fail("null is not a valid data array.");
175         } catch (IllegalArgumentException ex) {
176             // success
177         }
178         
179         // test empty
180         x = new double[] {};
181         TestUtils.assertEquals(Double.NaN, StatUtils.product(x), tolerance);
182         TestUtils.assertEquals(Double.NaN, StatUtils.product(x, 0, 0), tolerance);
183         
184         // test one
185         x = new double[] {two};
186         TestUtils.assertEquals(two, StatUtils.product(x), tolerance);
187         TestUtils.assertEquals(two, StatUtils.product(x, 0, 1), tolerance);
188         
189         // test many
190         x = new double[] {one, two, two, three};
191         TestUtils.assertEquals(12, StatUtils.product(x), tolerance);
192         TestUtils.assertEquals(4, StatUtils.product(x, 1, 2), tolerance);
193     }
194     
195     public void testSumLog() {
196         double[] x = null;
197         
198         // test null
199         try {
200             StatUtils.sumLog(x);
201             fail("null is not a valid data array.");
202         } catch (IllegalArgumentException ex) {
203             // success
204         }
205         
206         try {
207             StatUtils.sumLog(x, 0, 4);
208             fail("null is not a valid data array.");
209         } catch (IllegalArgumentException ex) {
210             // success
211         }
212         
213         // test empty
214         x = new double[] {};
215         TestUtils.assertEquals(Double.NaN, StatUtils.sumLog(x), tolerance);
216         TestUtils.assertEquals(Double.NaN, StatUtils.sumLog(x, 0, 0), tolerance);
217         
218         // test one
219         x = new double[] {two};
220         TestUtils.assertEquals(Math.log(two), StatUtils.sumLog(x), tolerance);
221         TestUtils.assertEquals(Math.log(two), StatUtils.sumLog(x, 0, 1), tolerance);
222         
223         // test many
224         x = new double[] {one, two, two, three};
225         TestUtils.assertEquals(Math.log(one) + 2.0 * Math.log(two) + Math.log(three), StatUtils.sumLog(x), tolerance);
226         TestUtils.assertEquals(2.0 * Math.log(two), StatUtils.sumLog(x, 1, 2), tolerance);
227     }
228     
229     public void testMean() {
230         double[] x = null;
231         
232         try {
233             StatUtils.mean(x, 0, 4);
234             fail("null is not a valid data array.");
235         } catch (IllegalArgumentException ex) {
236             // success
237         }
238         
239         // test empty
240         x = new double[] {};
241         TestUtils.assertEquals(Double.NaN, StatUtils.mean(x, 0, 0), tolerance);
242         
243         // test one
244         x = new double[] {two};
245         TestUtils.assertEquals(two, StatUtils.mean(x, 0, 1), tolerance);
246         
247         // test many
248         x = new double[] {one, two, two, three};
249         TestUtils.assertEquals(2.5, StatUtils.mean(x, 2, 2), tolerance);
250     }
251     
252     public void testVariance() {
253         double[] x = null;
254         
255         try {
256             StatUtils.variance(x, 0, 4);
257             fail("null is not a valid data array.");
258         } catch (IllegalArgumentException ex) {
259             // success
260         }
261         
262         // test empty
263         x = new double[] {};
264         TestUtils.assertEquals(Double.NaN, StatUtils.variance(x, 0, 0), tolerance);
265         
266         // test one
267         x = new double[] {two};
268         TestUtils.assertEquals(0.0, StatUtils.variance(x, 0, 1), tolerance);
269         
270         // test many
271         x = new double[] {one, two, two, three};
272         TestUtils.assertEquals(0.5, StatUtils.variance(x, 2, 2), tolerance);
273         
274         // test precomputed mean
275         x = new double[] {one, two, two, three};
276         TestUtils.assertEquals(0.5, StatUtils.variance(x,2.5, 2, 2), tolerance);
277     }
278     
279     public void testMax() {
280         double[] x = null;
281         
282         try {
283             StatUtils.max(x, 0, 4);
284             fail("null is not a valid data array.");
285         } catch (IllegalArgumentException ex) {
286             // success
287         }
288         
289         // test empty
290         x = new double[] {};
291         TestUtils.assertEquals(Double.NaN, StatUtils.max(x, 0, 0), tolerance);
292         
293         // test one
294         x = new double[] {two};
295         TestUtils.assertEquals(two, StatUtils.max(x, 0, 1), tolerance);
296         
297         // test many
298         x = new double[] {one, two, two, three};
299         TestUtils.assertEquals(three, StatUtils.max(x, 1, 3), tolerance);
300 
301         // test first nan is ignored
302         x = new double[] {nan, two, three};
303         TestUtils.assertEquals(three, StatUtils.max(x), tolerance);
304 
305         // test middle nan is ignored
306         x = new double[] {one, nan, three};
307         TestUtils.assertEquals(three, StatUtils.max(x), tolerance);
308         
309         // test last nan is ignored
310         x = new double[] {one, two, nan};
311         TestUtils.assertEquals(two, StatUtils.max(x), tolerance);
312 
313         // test all nan returns nan
314         x = new double[] {nan, nan, nan};
315         TestUtils.assertEquals(nan, StatUtils.max(x), tolerance);
316     }
317     
318     public void testMin() {
319         double[] x = null;
320         
321         try {
322             StatUtils.min(x, 0, 4);
323             fail("null is not a valid data array.");
324         } catch (IllegalArgumentException ex) {
325             // success
326         }
327         
328         // test empty
329         x = new double[] {};
330         TestUtils.assertEquals(Double.NaN, StatUtils.min(x, 0, 0), tolerance);
331         
332         // test one
333         x = new double[] {two};
334         TestUtils.assertEquals(two, StatUtils.min(x, 0, 1), tolerance);
335         
336         // test many
337         x = new double[] {one, two, two, three};
338         TestUtils.assertEquals(two, StatUtils.min(x, 1, 3), tolerance);
339 
340         // test first nan is ignored
341         x = new double[] {nan, two, three};
342         TestUtils.assertEquals(two, StatUtils.min(x), tolerance);
343 
344         // test middle nan is ignored
345         x = new double[] {one, nan, three};
346         TestUtils.assertEquals(one, StatUtils.min(x), tolerance);
347         
348         // test last nan is ignored
349         x = new double[] {one, two, nan};
350         TestUtils.assertEquals(one, StatUtils.min(x), tolerance);
351 
352         // test all nan returns nan
353         x = new double[] {nan, nan, nan};
354         TestUtils.assertEquals(nan, StatUtils.min(x), tolerance);
355     }
356     
357     public void testPercentile() {
358         double[] x = null;
359         
360         // test null
361         try {
362             StatUtils.percentile(x, .25);
363             fail("null is not a valid data array.");
364         } catch (IllegalArgumentException ex) {
365             // success
366         }
367         
368         try {
369             StatUtils.percentile(x, 0, 4, 0.25);
370             fail("null is not a valid data array.");
371         } catch (IllegalArgumentException ex) {
372             // success
373         }
374         
375         // test empty
376         x = new double[] {};
377         TestUtils.assertEquals(Double.NaN, StatUtils.percentile(x, 25), tolerance);
378         TestUtils.assertEquals(Double.NaN, StatUtils.percentile(x, 0, 0, 25), tolerance);
379         
380         // test one
381         x = new double[] {two};
382         TestUtils.assertEquals(two, StatUtils.percentile(x, 25), tolerance);
383         TestUtils.assertEquals(two, StatUtils.percentile(x, 0, 1, 25), tolerance);
384         
385         // test many
386         x = new double[] {one, two, two, three};
387         TestUtils.assertEquals(2.5, StatUtils.percentile(x, 70), tolerance);
388         TestUtils.assertEquals(2.5, StatUtils.percentile(x, 1, 3, 62.5), tolerance);
389     }
390     
391     public void testDifferenceStats() throws Exception {
392         double sample1[] = {1d, 2d, 3d, 4d};
393         double sample2[] = {1d, 3d, 4d, 2d};
394         double diff[] = {0d, -1d, -1d, 2d};
395         double small[] = {1d, 4d};
396         double meanDifference = StatUtils.meanDifference(sample1, sample2);
397         assertEquals(StatUtils.sumDifference(sample1, sample2), StatUtils.sum(diff), tolerance);
398         assertEquals(meanDifference, StatUtils.mean(diff), tolerance);
399         assertEquals(StatUtils.varianceDifference(sample1, sample2, meanDifference), 
400                 StatUtils.variance(diff), tolerance);
401         try {
402             StatUtils.meanDifference(sample1, small);
403             fail("Expecting IllegalArgumentException");
404         } catch (IllegalArgumentException ex) {
405             // expected
406         }
407         try {
408             StatUtils.varianceDifference(sample1, small, meanDifference);
409             fail("Expecting IllegalArgumentException");
410         } catch (IllegalArgumentException ex) {
411             // expected
412         }
413         try {
414             double[] single = {1.0};
415             StatUtils.varianceDifference(single, single, meanDifference);
416             fail("Expecting IllegalArgumentException");
417         } catch (IllegalArgumentException ex) {
418             // expected
419         }
420     }
421     
422     public void testGeometricMean() throws Exception {
423         double[] test = null;
424         try {
425             double x = StatUtils.geometricMean(test);
426             fail("Expecting IllegalArgumentException");
427         } catch (IllegalArgumentException ex) {
428             // expected
429         }
430         test = new double[] {2, 4, 6, 8};
431         assertEquals(Math.exp(0.25d * StatUtils.sumLog(test)), 
432                 StatUtils.geometricMean(test), Double.MIN_VALUE);
433         assertEquals(Math.exp(0.5 * StatUtils.sumLog(test, 0, 2)), 
434                 StatUtils.geometricMean(test, 0, 2), Double.MIN_VALUE);
435     }
436 }