1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
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
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 }