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