View Javadoc

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  
17  package org.apache.commons.math.random;
18  import java.io.BufferedReader;
19  import java.io.InputStreamReader;
20  import java.io.IOException;
21  import java.net.URL;
22  import java.net.MalformedURLException;
23  
24  /**
25   * Generates values for use in simulation applications.
26   * <p>
27   * How values are generated is determined by the <code>mode</code>
28   * property.
29   * <p>
30   * Supported <code>mode</code> values are: <ul>
31   * <li> DIGEST_MODE -- uses an empirical distribution </li>
32   * <li> REPLAY_MODE -- replays data from <code>valuesFileURL</code></li>
33   * <li> UNIFORM_MODE -- generates uniformly distributed random values with
34   *                      mean = <code>mu</code> </li>
35   * <li> EXPONENTIAL_MODE -- generates exponentially distributed random values
36   *                         with mean = <code>mu</code></li>
37   * <li> GAUSSIAN_MODE -- generates Gaussian distributed random values with
38   *                       mean = <code>mu</code> and
39   *                       standard deviation = <code>sigma</code></li>
40   * <li> CONSTANT_MODE -- returns <code>mu</code> every time.</li></ul>
41   *
42   * @version $Revision: 171283 $ $Date: 2005-05-21 22:25:44 -0700 (Sat, 21 May 2005) $
43   *
44   */
45  public class ValueServer {
46      /** mode determines how values are generated */
47      private int mode = 5;
48  
49      /** URI to raw data values  */
50      private URL valuesFileURL = null;
51  
52      /** Mean for use with non-data-driven modes */
53      private double mu = 0.0;
54  
55      /** Standard deviation for use with GAUSSIAN_MODE */
56      private double sigma = 0.0;
57  
58      /** Empirical probability distribution for use with DIGEST_MODE */
59      private EmpiricalDistribution empiricalDistribution = null;
60  
61      /** file pointer for REPLAY_MODE */
62      private BufferedReader filePointer = null;
63  
64      /** RandomDataImpl to use for random data generation */
65      private RandomData randomData = new RandomDataImpl();
66  
67      // Data generation modes ======================================
68  
69      /** Use empirical distribution  */
70      public static final int DIGEST_MODE = 0;
71  
72      /** Replay data from valuesFilePath */
73      public static final int REPLAY_MODE = 1;
74  
75      /** Uniform random deviates with mean = mu */
76      public static final int UNIFORM_MODE = 2;
77  
78      /** Exponential random deviates with mean = mu */
79      public static final int EXPONENTIAL_MODE = 3;
80  
81      /** Gaussian random deviates with mean = mu, std dev = sigma */
82      public static final int GAUSSIAN_MODE = 4;
83  
84      /** Always return mu */
85      public static final int CONSTANT_MODE = 5;
86  
87      /** Creates new ValueServer */
88      public ValueServer() {
89      }
90  
91      /**
92       * Returns the next generated value, generated according
93       * to the mode value (see MODE constants).
94       *
95       * @return generated value
96       * @throws IOException in REPLAY_MODE if a file I/O error occurs
97       */
98      public double getNext() throws IOException {
99          switch (mode) {
100             case DIGEST_MODE: return getNextDigest();
101             case REPLAY_MODE: return getNextReplay();
102             case UNIFORM_MODE: return getNextUniform();
103             case EXPONENTIAL_MODE: return getNextExponential();
104             case GAUSSIAN_MODE: return getNextGaussian();
105             case CONSTANT_MODE: return mu;
106             default: throw new IllegalStateException
107                        ("Bad mode: " + mode);
108         }
109     }
110 
111     /**
112      * Fills the input array with values generated using getNext() repeatedly.
113      *
114      * @param values array to be filled
115      * @throws IOException in REPLAY_MODE if a file I/O error occurs
116      */
117     public void fill(double[] values) throws IOException {
118         for (int i = 0; i < values.length; i++) {
119             values[i] = getNext();
120         }
121     }
122 
123     /**
124      * Returns an array of length <code>length</code> with values generated
125      * using getNext() repeatedly.
126      *
127      * @param length length of output array
128      * @return array of generated values
129      * @throws IOException in REPLAY_MODE if a file I/O error occurs
130      */
131     public double[] fill(int length) throws IOException {
132         double[] out = new double[length];
133         for (int i = 0; i < length; i++) {
134             out[i] = getNext();
135         }
136         return out;
137     }
138 
139     /**
140      * Computes the empirical distribution using values from the file
141      * in <code>valuesFileURL</code>, using the default number of bins.
142      * <p>
143      * <code>valuesFileURL</code> must exist and be
144      * readable by *this at runtime.
145      * <p>
146      * This method must be called before using <code>getNext()</code>
147      * with <code>mode = DISGEST_MODE</code>
148      *
149      * @throws IOException if an I/O error occurs reading the input file
150      */
151     public void computeDistribution() throws IOException {
152         empiricalDistribution = new EmpiricalDistributionImpl();
153         empiricalDistribution.load(valuesFileURL);
154     }
155 
156     /**
157      * Computes the empirical distribution using values from the file
158      * in <code>valuesFileURL</code> and <code>binCount</code> bins.
159      * <p>
160      * <code>valuesFileURL</code> must exist and be
161      * readable by *this at runtime.
162      * <p>
163      * This method must be called before using <code>getNext()</code>
164      * with <code>mode = DISGEST_MODE</code>
165      *
166      * @param binCount the number of bins used in computing the empirical
167      * distribution
168      * @throws IOException if an error occurs reading the input file
169      */
170     public void computeDistribution(int binCount)
171             throws IOException {
172         empiricalDistribution = new EmpiricalDistributionImpl(binCount);
173         empiricalDistribution.load(valuesFileURL);
174         mu = empiricalDistribution.getSampleStats().getMean();
175         sigma = empiricalDistribution.getSampleStats().getStandardDeviation();
176     }
177 
178     /** Getter for property mode.
179      * @return Value of property mode.
180      */
181     public int getMode() {
182         return mode;
183     }
184 
185     /** Setter for property mode.
186      * @param mode New value of property mode.
187      */
188     public void setMode(int mode) {
189         this.mode = mode;
190     }
191 
192     /**
193      * Getter for <code>valuesFileURL<code>
194      * @return Value of property valuesFileURL.
195      */
196     public URL getValuesFileURL() {
197         return valuesFileURL;
198     }
199 
200     /**
201      * Sets the <code>valuesFileURL</code> using a string URL representation
202      * @param url String representation for new valuesFileURL.
203      * @throws MalformedURLException if url is not well formed
204      */
205     public void setValuesFileURL(String url) throws MalformedURLException {
206         this.valuesFileURL = new URL(url);
207     }
208 
209     /**
210      * Sets the <code>valuesFileURL</code>
211      * @param url New value of property valuesFileURL.
212      */
213     public void setValuesFileURL(URL url) {
214         this.valuesFileURL = url;
215     }
216 
217     /** Getter for property empiricalDistribution.
218      * @return Value of property empiricalDistribution.
219      */
220     public EmpiricalDistribution getEmpiricalDistribution() {
221         return empiricalDistribution;
222     }
223 
224     /**
225      * Resets REPLAY_MODE file pointer to the beginning of the <code>valuesFileURL</code>.
226      *
227      * @throws IOException if an error occurs opening the file
228      */
229     public void resetReplayFile() throws IOException {
230         if (filePointer != null) {
231             try {
232                 filePointer.close();
233                 filePointer = null;
234             } catch (IOException ex) {
235                 // ignore
236             }
237         }
238         filePointer = new BufferedReader(new InputStreamReader(valuesFileURL.openStream()));
239     }
240 
241     /**
242      * Closes <code>valuesFileURL</code> after use in REPLAY_MODE.
243      *
244      * @throws IOException if an error occurs closing the file
245      */
246     public void closeReplayFile() throws IOException {
247         if (filePointer != null) {
248             filePointer.close();
249             filePointer = null;
250         }
251     }
252 
253     /** Getter for property mu.
254      * @return Value of property mu.
255      */
256     public double getMu() {
257         return mu;
258     }
259 
260     /** Setter for property mu.
261      * @param mu New value of property mu.
262      */
263     public void setMu(double mu) {
264         this.mu = mu;
265     }
266 
267     /** Getter for property sigma.
268      * @return Value of property sigma.
269      */
270     public double getSigma() {
271         return sigma;
272     }
273 
274     /** Setter for property sigma.
275      * @param sigma New value of property sigma.
276      */
277     public void setSigma(double sigma) {
278         this.sigma = sigma;
279     }
280 
281     //------------- private methods ---------------------------------
282 
283     /**
284      * Gets a random value in DIGEST_MODE.
285      * <p>
286      * <strong>Preconditions</strong>: <ul>
287      * <li>Before this method is called, <code>computeDistribution()</code>
288      * must have completed successfully; otherwise an
289      * <code>IllegalStateException</code> will be thrown</li></ul>
290      *
291      * @return next random value from the empirical distribution digest
292      */
293     private double getNextDigest() {
294         if ((empiricalDistribution == null) ||
295             (empiricalDistribution.getBinStats().size() == 0)) {
296             throw new IllegalStateException("Digest not initialized");
297         }
298         return empiricalDistribution.getNextValue();
299     }
300 
301     /**
302      * Gets next sequential value from the <code>valuesFileURL</code>.
303      * <p>
304      * Throws an IOException if the read fails.
305      * <p>
306      * This method will open the <code>valuesFileURL</code> if there is no
307      * replay file open.
308      * <p>
309      * The <code>valuesFileURL</code> will be closed and reopened to wrap around
310      * from EOF to BOF if EOF is encountered.
311      *
312      * @return next value from the replay file
313      * @throws IOException if there is a problem reading from the file
314      */
315     private double getNextReplay() throws IOException {
316         String str = null;
317         if (filePointer == null) {
318             resetReplayFile();
319         }
320         if ((str = filePointer.readLine()) == null) {
321             closeReplayFile();
322             resetReplayFile();
323             str = filePointer.readLine();
324         }
325         return new Double(str).doubleValue();
326     }
327 
328     /**
329      * Gets a uniformly distributed random value with mean = mu.
330      *
331      * @return random uniform value
332      */
333     private double getNextUniform() {
334         return randomData.nextUniform(0, 2 * mu);
335     }
336 
337     /**
338      * Gets an exponentially distributed random value with mean = mu.
339      *
340      * @return random exponential value
341      */
342     private double getNextExponential() {
343         return randomData.nextExponential(mu);
344     }
345 
346     /**
347      * Gets a Gaussian distributed random value with mean = mu
348      * and standard deviation = sigma.
349      *
350      * @return random Gaussian value
351      */
352     private double getNextGaussian() {
353         return randomData.nextGaussian(mu, sigma);
354     }
355 
356     /**
357      * Construct a ValueServer instance using a RandomData as its source
358      * of random data.
359      * 
360      * @param randomData the RandomData instance used to source random data
361      * @since 1.1
362      */
363     public ValueServer(RandomData randomData) {
364         super();
365         this.randomData = randomData;
366     }
367 }