001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math.stat;
018    
019    import junit.framework.Test;
020    import junit.framework.TestCase;
021    import junit.framework.TestSuite;
022    
023    import org.apache.commons.math.TestUtils;
024    
025    /**
026     * Test cases for the {@link StatUtils} class.
027     * @version $Revision: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
028     */
029    
030    public final class StatUtilsTest extends TestCase {
031    
032        private double one = 1;
033        private float two = 2;
034        private int three = 3;
035        private double mean = 2;
036        private double sumSq = 18;
037        private double sum = 8;
038        private double var = 0.666666666666666666667;
039        private double min = 1;
040        private double max = 3;
041        private double tolerance = 10E-15;
042        private double nan = Double.NaN;
043    
044        public StatUtilsTest(String name) {
045            super(name);
046        }
047    
048        public static Test suite() {
049            TestSuite suite = new TestSuite(StatUtilsTest.class);
050            suite.setName("StatUtil Tests");
051            return suite;
052        }
053    
054        /** test stats */
055        public void testStats() {
056            double[] values = new double[] { one, two, two, three };
057            assertEquals("sum", sum, StatUtils.sum(values), tolerance);
058            assertEquals("sumsq", sumSq, StatUtils.sumSq(values), tolerance);
059            assertEquals("var", var, StatUtils.variance(values), tolerance);
060            assertEquals("var with mean", var, StatUtils.variance(values, mean), tolerance);
061            assertEquals("mean", mean, StatUtils.mean(values), tolerance);
062            assertEquals("min", min, StatUtils.min(values), tolerance);
063            assertEquals("max", max, StatUtils.max(values), tolerance);
064        }
065    
066        public void testN0andN1Conditions() throws Exception {
067            double[] values = new double[0];
068    
069            assertTrue(
070                "Mean of n = 0 set should be NaN",
071                Double.isNaN(StatUtils.mean(values)));
072            assertTrue(
073                "Variance of n = 0 set should be NaN",
074                Double.isNaN(StatUtils.variance(values)));
075    
076            values = new double[] { one };
077    
078            assertTrue(
079                "Mean of n = 1 set should be value of single item n1",
080                StatUtils.mean(values) == one);
081            assertTrue(
082                "Variance of n = 1 set should be zero",
083                StatUtils.variance(values) == 0);
084        }
085    
086        public void testArrayIndexConditions() throws Exception {
087            double[] values = { 1.0, 2.0, 3.0, 4.0 };
088    
089            assertEquals(
090                "Sum not expected",
091                5.0,
092                StatUtils.sum(values, 1, 2),
093                Double.MIN_VALUE);
094            assertEquals(
095                "Sum not expected",
096                3.0,
097                StatUtils.sum(values, 0, 2),
098                Double.MIN_VALUE);
099            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    }