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: 1.17 $ $Date: 2004/08/22 01:41:30 $
    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 RandomDataImpl 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 }