1   /*
2    * Copyright 2003-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.math.random;
17  
18  import junit.framework.Test;
19  import junit.framework.TestSuite;
20  
21  import java.io.BufferedReader;
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.InputStreamReader;
25  import java.net.URL;
26  import java.util.ArrayList;
27  import java.util.Iterator;
28  
29  import org.apache.commons.math.RetryTestCase;
30  import org.apache.commons.math.TestUtils;
31  import org.apache.commons.math.stat.descriptive.SummaryStatistics;
32  
33  /**
34   * Test cases for the EmpiricalDistribution class
35   *
36   * @version $Revision: 348772 $ $Date: 2005-11-24 10:26:34 -0700 (Thu, 24 Nov 2005) $
37   */
38  
39  public final class EmpiricalDistributionTest extends RetryTestCase {
40  
41      protected EmpiricalDistribution empiricalDistribution = null;
42      protected EmpiricalDistribution empiricalDistribution2 = null;
43      protected File file = null;
44      protected URL url = null; 
45      protected double[] dataArray = null;
46      
47      public EmpiricalDistributionTest(String name) {
48          super(name);
49      }
50  
51      public void setUp() throws IOException {
52          empiricalDistribution = new EmpiricalDistributionImpl(100);
53          url = getClass().getResource("testData.txt");
54          
55          empiricalDistribution2 = new EmpiricalDistributionImpl(100);
56          BufferedReader in = 
57                  new BufferedReader(new InputStreamReader(
58                          url.openStream()));
59          String str = null;
60          ArrayList list = new ArrayList();
61          while ((str = in.readLine()) != null) {
62              list.add(Double.valueOf(str));
63          }
64          in.close();
65          in = null;
66          
67          dataArray = new double[list.size()];
68          int i = 0;
69          for (Iterator iter = list.iterator(); iter.hasNext();) {
70              dataArray[i] = ((Double)iter.next()).doubleValue();
71              i++;
72          }                 
73      }
74  
75      public static Test suite() {
76          TestSuite suite = new TestSuite(EmpiricalDistributionTest.class);
77          suite.setName("EmpiricalDistribution Tests");
78          return suite;
79      }
80  
81      /**
82       * Test EmpiricalDistrbution.load() using sample data file.<br> 
83       * Check that the sampleCount, mu and sigma match data in 
84       * the sample data file.
85       */
86      public void testLoad() throws Exception {
87          empiricalDistribution.load(url);   
88          // testData File has 10000 values, with mean ~ 5.0, std dev ~ 1
89          // Make sure that loaded distribution matches this
90          assertEquals(empiricalDistribution.getSampleStats().getN(),1000,10E-7);
91          //TODO: replace with statistical tests
92          assertEquals
93              (empiricalDistribution.getSampleStats().getMean(),
94                  5.069831575018909,10E-7);
95          assertEquals
96            (empiricalDistribution.getSampleStats().getStandardDeviation(),
97                  1.0173699343977738,10E-7);
98      }
99  
100     /**
101      * Test EmpiricalDistrbution.load(double[]) using data taken from
102      * sample data file.<br> 
103      * Check that the sampleCount, mu and sigma match data in 
104      * the sample data file.
105      */
106     public void testDoubleLoad() throws Exception {
107         empiricalDistribution2.load(dataArray);   
108         // testData File has 10000 values, with mean ~ 5.0, std dev ~ 1
109         // Make sure that loaded distribution matches this
110         assertEquals(empiricalDistribution2.getSampleStats().getN(),1000,10E-7);
111         //TODO: replace with statistical tests
112         assertEquals
113             (empiricalDistribution2.getSampleStats().getMean(),
114                 5.069831575018909,10E-7);
115         assertEquals
116           (empiricalDistribution2.getSampleStats().getStandardDeviation(),
117                 1.0173699343977738,10E-7);
118         
119         double[] bounds = empiricalDistribution2.getUpperBounds();
120         assertEquals(bounds.length, 100);
121         assertEquals(bounds[99], 1.0, 10e-12);
122           
123     }
124    
125     /** 
126       * Generate 1000 random values and make sure they look OK.<br>
127       * Note that there is a non-zero (but very small) probability that
128       * these tests will fail even if the code is working as designed.
129       */
130     public void testNext() throws Exception {
131         tstGen(0.1);
132         tstDoubleGen(0.1);
133     }
134     
135     /**
136       * Make sure exception thrown if digest getNext is attempted
137       * before loading empiricalDistribution.
138      */
139     public void testNexFail() {
140         try {
141             empiricalDistribution.getNextValue();
142             empiricalDistribution2.getNextValue();
143             fail("Expecting IllegalStateException");
144         } catch (IllegalStateException ex) {;}
145     }
146     
147     /**
148      * Make sure we can handle a grid size that is too fine
149      */
150     public void testGridTooFine() throws Exception {
151         empiricalDistribution = new EmpiricalDistributionImpl(1001);
152         tstGen(0.1);    
153         empiricalDistribution2 = new EmpiricalDistributionImpl(1001);           
154         tstDoubleGen(0.1);
155     }
156     
157     /**
158      * How about too fat?
159      */
160     public void testGridTooFat() throws Exception {
161         empiricalDistribution = new EmpiricalDistributionImpl(1);
162         tstGen(5); // ridiculous tolerance; but ridiculous grid size
163                    // really just checking to make sure we do not bomb
164         empiricalDistribution2 = new EmpiricalDistributionImpl(1);           
165         tstDoubleGen(5);           
166     }
167     
168     /**
169      * Test bin index overflow problem (BZ 36450)
170      */
171     public void testBinIndexOverflow() throws Exception {
172         double[] x = new double[] {9474.94326071674, 2080107.8865462579};
173         new EmpiricalDistributionImpl().load(x);
174     }
175     
176     public void testSerialization() {
177         // Empty
178         EmpiricalDistribution dist = new EmpiricalDistributionImpl();
179         EmpiricalDistribution dist2 = (EmpiricalDistribution) TestUtils.serializeAndRecover(dist);
180         verifySame(dist, dist2);
181         
182         // Loaded
183         empiricalDistribution2.load(dataArray);   
184         dist2 = (EmpiricalDistribution) TestUtils.serializeAndRecover(empiricalDistribution2);
185         verifySame(empiricalDistribution2, dist2);
186     }
187     
188     private void verifySame(EmpiricalDistribution d1, EmpiricalDistribution d2) {
189         assertEquals(d1.isLoaded(), d2.isLoaded());
190         assertEquals(d1.getBinCount(), d2.getBinCount());
191         assertEquals(d1.getSampleStats(), d2.getSampleStats());
192         if (d1.isLoaded()) {
193             for (int i = 0;  i < d1.getUpperBounds().length; i++) {
194                 assertEquals(d1.getUpperBounds()[i], d2.getUpperBounds()[i], 0);
195             }
196             assertEquals(d1.getBinStats(), d2.getBinStats());
197         }
198     }
199     
200     private void tstGen(double tolerance)throws Exception {
201         empiricalDistribution.load(url);   
202         SummaryStatistics stats = SummaryStatistics.newInstance();
203         for (int i = 1; i < 1000; i++) {
204             stats.addValue(empiricalDistribution.getNextValue());
205         }
206         assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
207         assertEquals
208          ("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
209     }
210 
211     private void tstDoubleGen(double tolerance)throws Exception {
212         empiricalDistribution2.load(dataArray);   
213         SummaryStatistics stats = SummaryStatistics.newInstance();
214         for (int i = 1; i < 1000; i++) {
215             stats.addValue(empiricalDistribution2.getNextValue());
216         }
217         assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
218         assertEquals
219          ("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
220     }
221 }