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.random;
018    
019    import java.io.BufferedReader;
020    import java.io.File;
021    import java.io.IOException;
022    import java.io.InputStreamReader;
023    import java.net.URL;
024    import java.util.ArrayList;
025    
026    import junit.framework.Test;
027    import junit.framework.TestSuite;
028    
029    import org.apache.commons.math.MathRuntimeException;
030    import org.apache.commons.math.RetryTestCase;
031    import org.apache.commons.math.TestUtils;
032    import org.apache.commons.math.stat.descriptive.SummaryStatistics;
033    
034    /**
035     * Test cases for the EmpiricalDistribution class
036     *
037     * @version $Revision: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
038     */
039    
040    public final class EmpiricalDistributionTest extends RetryTestCase {
041    
042        protected EmpiricalDistribution empiricalDistribution = null;
043        protected EmpiricalDistribution empiricalDistribution2 = null;
044        protected File file = null;
045        protected URL url = null; 
046        protected double[] dataArray = null;
047        
048        public EmpiricalDistributionTest(String name) {
049            super(name);
050        }
051    
052        @Override
053        public void setUp() throws IOException {
054            empiricalDistribution = new EmpiricalDistributionImpl(100);
055            url = getClass().getResource("testData.txt");
056            
057            empiricalDistribution2 = new EmpiricalDistributionImpl(100);
058            BufferedReader in = 
059                    new BufferedReader(new InputStreamReader(
060                            url.openStream()));
061            String str = null;
062            ArrayList<Double> list = new ArrayList<Double>();
063            while ((str = in.readLine()) != null) {
064                list.add(Double.valueOf(str));
065            }
066            in.close();
067            in = null;
068            
069            dataArray = new double[list.size()];
070            int i = 0;
071            for (Double data : list) {
072                dataArray[i] = data.doubleValue();
073                i++;
074            }                 
075        }
076    
077        public static Test suite() {
078            TestSuite suite = new TestSuite(EmpiricalDistributionTest.class);
079            suite.setName("EmpiricalDistribution Tests");
080            return suite;
081        }
082    
083        /**
084         * Test EmpiricalDistrbution.load() using sample data file.<br> 
085         * Check that the sampleCount, mu and sigma match data in 
086         * the sample data file.
087         */
088        public void testLoad() throws Exception {
089            empiricalDistribution.load(url);   
090            // testData File has 10000 values, with mean ~ 5.0, std dev ~ 1
091            // Make sure that loaded distribution matches this
092            assertEquals(empiricalDistribution.getSampleStats().getN(),1000,10E-7);
093            //TODO: replace with statistical tests
094            assertEquals
095                (empiricalDistribution.getSampleStats().getMean(),
096                    5.069831575018909,10E-7);
097            assertEquals
098              (empiricalDistribution.getSampleStats().getStandardDeviation(),
099                    1.0173699343977738,10E-7);
100        }
101    
102        /**
103         * Test EmpiricalDistrbution.load(double[]) using data taken from
104         * sample data file.<br> 
105         * Check that the sampleCount, mu and sigma match data in 
106         * the sample data file.
107         */
108        public void testDoubleLoad() throws Exception {
109            empiricalDistribution2.load(dataArray);   
110            // testData File has 10000 values, with mean ~ 5.0, std dev ~ 1
111            // Make sure that loaded distribution matches this
112            assertEquals(empiricalDistribution2.getSampleStats().getN(),1000,10E-7);
113            //TODO: replace with statistical tests
114            assertEquals
115                (empiricalDistribution2.getSampleStats().getMean(),
116                    5.069831575018909,10E-7);
117            assertEquals
118              (empiricalDistribution2.getSampleStats().getStandardDeviation(),
119                    1.0173699343977738,10E-7);
120            
121            double[] bounds = empiricalDistribution2.getUpperBounds();
122            assertEquals(bounds.length, 100);
123            assertEquals(bounds[99], 1.0, 10e-12);
124              
125        }
126       
127        /** 
128          * Generate 1000 random values and make sure they look OK.<br>
129          * Note that there is a non-zero (but very small) probability that
130          * these tests will fail even if the code is working as designed.
131          */
132        public void testNext() throws Exception {
133            tstGen(0.1);
134            tstDoubleGen(0.1);
135        }
136        
137        /**
138          * Make sure exception thrown if digest getNext is attempted
139          * before loading empiricalDistribution.
140         */
141        public void testNexFail() {
142            try {
143                empiricalDistribution.getNextValue();
144                empiricalDistribution2.getNextValue();
145                fail("Expecting IllegalStateException");
146            } catch (IllegalStateException ex) {
147                // expected
148            } catch (Exception e) {
149                fail("wrong exception caught");
150            }
151        }
152        
153        /**
154         * Make sure we can handle a grid size that is too fine
155         */
156        public void testGridTooFine() throws Exception {
157            empiricalDistribution = new EmpiricalDistributionImpl(1001);
158            tstGen(0.1);    
159            empiricalDistribution2 = new EmpiricalDistributionImpl(1001);           
160            tstDoubleGen(0.1);
161        }
162        
163        /**
164         * How about too fat?
165         */
166        public void testGridTooFat() throws Exception {
167            empiricalDistribution = new EmpiricalDistributionImpl(1);
168            tstGen(5); // ridiculous tolerance; but ridiculous grid size
169                       // really just checking to make sure we do not bomb
170            empiricalDistribution2 = new EmpiricalDistributionImpl(1);           
171            tstDoubleGen(5);           
172        }
173        
174        /**
175         * Test bin index overflow problem (BZ 36450)
176         */
177        public void testBinIndexOverflow() throws Exception {
178            double[] x = new double[] {9474.94326071674, 2080107.8865462579};
179            new EmpiricalDistributionImpl().load(x);
180        }
181        
182        public void testSerialization() {
183            // Empty
184            EmpiricalDistribution dist = new EmpiricalDistributionImpl();
185            EmpiricalDistribution dist2 = (EmpiricalDistribution) TestUtils.serializeAndRecover(dist);
186            verifySame(dist, dist2);
187            
188            // Loaded
189            empiricalDistribution2.load(dataArray);   
190            dist2 = (EmpiricalDistribution) TestUtils.serializeAndRecover(empiricalDistribution2);
191            verifySame(empiricalDistribution2, dist2);
192        }
193    
194        public void testLoadNullDoubleArray() {
195            EmpiricalDistribution dist = new EmpiricalDistributionImpl();
196            try {
197                dist.load((double[]) null);
198                fail("load((double[]) null) expected RuntimeException");
199            } catch (MathRuntimeException e) {
200                // expected
201            } catch (Exception e) {
202                fail("wrong exception caught");
203            }
204        }
205    
206        public void testLoadNullURL() throws Exception {
207            EmpiricalDistribution dist = new EmpiricalDistributionImpl();
208            try {
209                dist.load((URL) null);
210                fail("load((URL) null) expected NullPointerException");
211            } catch (NullPointerException e) {
212                // expected
213            } catch (Exception e) {
214                fail("wrong exception caught");
215            }
216        }
217    
218        public void testLoadNullFile() throws Exception {
219            EmpiricalDistribution dist = new EmpiricalDistributionImpl();
220            try {
221                dist.load((File) null);
222                fail("load((File) null) expected NullPointerException");
223            } catch (NullPointerException e) {
224                // expected
225            } catch (Exception e) {
226                fail("wrong exception caught");
227            }
228        }
229    
230        private void verifySame(EmpiricalDistribution d1, EmpiricalDistribution d2) {
231            assertEquals(d1.isLoaded(), d2.isLoaded());
232            assertEquals(d1.getBinCount(), d2.getBinCount());
233            assertEquals(d1.getSampleStats(), d2.getSampleStats());
234            if (d1.isLoaded()) {
235                for (int i = 0;  i < d1.getUpperBounds().length; i++) {
236                    assertEquals(d1.getUpperBounds()[i], d2.getUpperBounds()[i], 0);
237                }
238                assertEquals(d1.getBinStats(), d2.getBinStats());
239            }
240        }
241        
242        private void tstGen(double tolerance)throws Exception {
243            empiricalDistribution.load(url);   
244            SummaryStatistics stats = new SummaryStatistics();
245            for (int i = 1; i < 1000; i++) {
246                stats.addValue(empiricalDistribution.getNextValue());
247            }
248            assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
249            assertEquals
250             ("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
251        }
252    
253        private void tstDoubleGen(double tolerance)throws Exception {
254            empiricalDistribution2.load(dataArray);   
255            SummaryStatistics stats = new SummaryStatistics();
256            for (int i = 1; i < 1000; i++) {
257                stats.addValue(empiricalDistribution2.getNextValue());
258            }
259            assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
260            assertEquals
261             ("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
262        }
263    }