001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with this
004     * work for additional information regarding copyright ownership. The ASF
005     * licenses this file to You under the Apache License, Version 2.0 (the
006     * "License"); you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
009     * or agreed to in writing, software distributed under the License is
010     * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
011     * KIND, either express or implied. See the License for the specific language
012     * governing permissions and limitations under the License.
013     */
014    package org.apache.commons.math.stat.descriptive;
015    
016    import java.util.Locale;
017    
018    import junit.framework.Test;
019    import junit.framework.TestCase;
020    import junit.framework.TestSuite;
021    
022    import org.apache.commons.math.stat.descriptive.rank.Percentile;
023    import org.apache.commons.math.util.MathUtils;
024    
025    /**
026     * Test cases for the DescriptiveStatistics class.
027     * 
028     * @version $Revision: 797742 $ $Date: 2007-08-16 15:36:33 -0500 (Thu, 16 Aug
029     *          2007) $
030     */
031    public class DescriptiveStatisticsTest extends TestCase {
032    
033        public DescriptiveStatisticsTest(String name) {
034            super(name);
035        }
036    
037        public static Test suite() {
038            TestSuite suite = new TestSuite(DescriptiveStatisticsTest.class);
039            suite.setName("DescriptiveStatistics Tests");
040            return suite;
041        }
042    
043        protected DescriptiveStatistics createDescriptiveStatistics() {
044            return new DescriptiveStatistics();
045        }
046    
047        public void testSetterInjection() {
048            DescriptiveStatistics stats = createDescriptiveStatistics();
049            stats.addValue(1);
050            stats.addValue(3);
051            assertEquals(2, stats.getMean(), 1E-10);
052            // Now lets try some new math
053            stats.setMeanImpl(new deepMean());
054            assertEquals(42, stats.getMean(), 1E-10);
055        }
056        
057        public void testCopy() {
058            DescriptiveStatistics stats = createDescriptiveStatistics();
059            stats.addValue(1);
060            stats.addValue(3);
061            DescriptiveStatistics copy = new DescriptiveStatistics(stats);
062            assertEquals(2, copy.getMean(), 1E-10);
063            // Now lets try some new math
064            stats.setMeanImpl(new deepMean());
065            copy = stats.copy();
066            assertEquals(42, copy.getMean(), 1E-10);
067        }
068        
069        public void testWindowSize() {
070            DescriptiveStatistics stats = createDescriptiveStatistics();
071            stats.setWindowSize(300);
072            for (int i = 0; i < 100; ++i) {
073                stats.addValue(i + 1);
074            }
075            int refSum = (100 * 101) / 2;
076            assertEquals(refSum / 100.0, stats.getMean(), 1E-10);
077            assertEquals(300, stats.getWindowSize());
078            try {
079                stats.setWindowSize(-3);
080                fail("an exception should have been thrown");
081            } catch (IllegalArgumentException iae) {
082                // expected
083            } catch (Exception e) {
084                fail("wrong exception caught: " + e.getMessage());
085            }
086            assertEquals(300, stats.getWindowSize());
087            stats.setWindowSize(50);
088            assertEquals(50, stats.getWindowSize());
089            int refSum2 = refSum - (50 * 51) / 2;
090            assertEquals(refSum2 / 50.0, stats.getMean(), 1E-10);
091        }
092        
093        public void testGetValues() {
094            DescriptiveStatistics stats = createDescriptiveStatistics();
095            for (int i = 100; i > 0; --i) {
096                stats.addValue(i);
097            }
098            int refSum = (100 * 101) / 2;
099            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    }