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 }