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.random;
18  
19  import java.io.BufferedReader;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStreamReader;
23  import java.net.URL;
24  import java.util.ArrayList;
25  
26  import junit.framework.Test;
27  import junit.framework.TestSuite;
28  
29  import org.apache.commons.math.MathRuntimeException;
30  import org.apache.commons.math.RetryTestCase;
31  import org.apache.commons.math.TestUtils;
32  import org.apache.commons.math.stat.descriptive.SummaryStatistics;
33  
34  /**
35   * Test cases for the EmpiricalDistribution class
36   *
37   * @version $Revision: 762087 $ $Date: 2009-04-05 10:20:18 -0400 (Sun, 05 Apr 2009) $
38   */
39  
40  public final class EmpiricalDistributionTest extends RetryTestCase {
41  
42      protected EmpiricalDistribution empiricalDistribution = null;
43      protected EmpiricalDistribution empiricalDistribution2 = null;
44      protected File file = null;
45      protected URL url = null; 
46      protected double[] dataArray = null;
47      
48      public EmpiricalDistributionTest(String name) {
49          super(name);
50      }
51  
52      @Override
53      public void setUp() throws IOException {
54          empiricalDistribution = new EmpiricalDistributionImpl(100);
55          url = getClass().getResource("testData.txt");
56          
57          empiricalDistribution2 = new EmpiricalDistributionImpl(100);
58          BufferedReader in = 
59                  new BufferedReader(new InputStreamReader(
60                          url.openStream()));
61          String str = null;
62          ArrayList<Double> list = new ArrayList<Double>();
63          while ((str = in.readLine()) != null) {
64              list.add(Double.valueOf(str));
65          }
66          in.close();
67          in = null;
68          
69          dataArray = new double[list.size()];
70          int i = 0;
71          for (Double data : list) {
72              dataArray[i] = data.doubleValue();
73              i++;
74          }                 
75      }
76  
77      public static Test suite() {
78          TestSuite suite = new TestSuite(EmpiricalDistributionTest.class);
79          suite.setName("EmpiricalDistribution Tests");
80          return suite;
81      }
82  
83      /**
84       * Test EmpiricalDistrbution.load() using sample data file.<br> 
85       * Check that the sampleCount, mu and sigma match data in 
86       * the sample data file.
87       */
88      public void testLoad() throws Exception {
89          empiricalDistribution.load(url);   
90          // testData File has 10000 values, with mean ~ 5.0, std dev ~ 1
91          // Make sure that loaded distribution matches this
92          assertEquals(empiricalDistribution.getSampleStats().getN(),1000,10E-7);
93          //TODO: replace with statistical tests
94          assertEquals
95              (empiricalDistribution.getSampleStats().getMean(),
96                  5.069831575018909,10E-7);
97          assertEquals
98            (empiricalDistribution.getSampleStats().getStandardDeviation(),
99                  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 }