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