All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.math3.random.ValueServer Maven / Gradle / Ivy

There is a newer version: 5.0.70
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.math3.random;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.math3.exception.MathIllegalArgumentException;
import org.apache.commons.math3.exception.MathIllegalStateException;
import org.apache.commons.math3.exception.NullArgumentException;
import org.apache.commons.math3.exception.ZeroException;
import org.apache.commons.math3.exception.util.LocalizedFormats;

/**
 * Generates values for use in simulation applications.
 * 

* How values are generated is determined by the mode * property.

*

* Supported mode values are:

    *
  • DIGEST_MODE -- uses an empirical distribution
  • *
  • REPLAY_MODE -- replays data from valuesFileURL
  • *
  • UNIFORM_MODE -- generates uniformly distributed random values with * mean = mu
  • *
  • EXPONENTIAL_MODE -- generates exponentially distributed random values * with mean = mu
  • *
  • GAUSSIAN_MODE -- generates Gaussian distributed random values with * mean = mu and * standard deviation = sigma
  • *
  • CONSTANT_MODE -- returns mu every time.

* * */ public class ValueServer { /** Use empirical distribution. */ public static final int DIGEST_MODE = 0; /** Replay data from valuesFilePath. */ public static final int REPLAY_MODE = 1; /** Uniform random deviates with mean = μ. */ public static final int UNIFORM_MODE = 2; /** Exponential random deviates with mean = μ. */ public static final int EXPONENTIAL_MODE = 3; /** Gaussian random deviates with mean = μ, std dev = σ. */ public static final int GAUSSIAN_MODE = 4; /** Always return mu */ public static final int CONSTANT_MODE = 5; /** mode determines how values are generated. */ private int mode = 5; /** URI to raw data values. */ private URL valuesFileURL = null; /** Mean for use with non-data-driven modes. */ private double mu = 0.0; /** Standard deviation for use with GAUSSIAN_MODE. */ private double sigma = 0.0; /** Empirical probability distribution for use with DIGEST_MODE. */ private EmpiricalDistribution empiricalDistribution = null; /** File pointer for REPLAY_MODE. */ private BufferedReader filePointer = null; /** RandomDataImpl to use for random data generation. */ private final RandomDataGenerator randomData; // Data generation modes ====================================== /** Creates new ValueServer */ public ValueServer() { randomData = new RandomDataGenerator(); } /** * Construct a ValueServer instance using a RandomDataImpl as its source * of random data. * * @param randomData the RandomDataImpl instance used to source random data * @since 3.0 * @deprecated use {@link #ValueServer(RandomGenerator)} */ @Deprecated public ValueServer(RandomDataImpl randomData) { this.randomData = randomData.getDelegate(); } /** * Construct a ValueServer instance using a RandomGenerator as its source * of random data. * * @since 3.1 * @param generator source of random data */ public ValueServer(RandomGenerator generator) { this.randomData = new RandomDataGenerator(generator); } /** * Returns the next generated value, generated according * to the mode value (see MODE constants). * * @return generated value * @throws IOException in REPLAY_MODE if a file I/O error occurs * @throws MathIllegalStateException if mode is not recognized * @throws MathIllegalArgumentException if the underlying random generator thwrows one */ public double getNext() throws IOException, MathIllegalStateException, MathIllegalArgumentException { switch (mode) { case DIGEST_MODE: return getNextDigest(); case REPLAY_MODE: return getNextReplay(); case UNIFORM_MODE: return getNextUniform(); case EXPONENTIAL_MODE: return getNextExponential(); case GAUSSIAN_MODE: return getNextGaussian(); case CONSTANT_MODE: return mu; default: throw new MathIllegalStateException( LocalizedFormats.UNKNOWN_MODE, mode, "DIGEST_MODE", DIGEST_MODE, "REPLAY_MODE", REPLAY_MODE, "UNIFORM_MODE", UNIFORM_MODE, "EXPONENTIAL_MODE", EXPONENTIAL_MODE, "GAUSSIAN_MODE", GAUSSIAN_MODE, "CONSTANT_MODE", CONSTANT_MODE); } } /** * Fills the input array with values generated using getNext() repeatedly. * * @param values array to be filled * @throws IOException in REPLAY_MODE if a file I/O error occurs * @throws MathIllegalStateException if mode is not recognized * @throws MathIllegalArgumentException if the underlying random generator thwrows one */ public void fill(double[] values) throws IOException, MathIllegalStateException, MathIllegalArgumentException { for (int i = 0; i < values.length; i++) { values[i] = getNext(); } } /** * Returns an array of length length with values generated * using getNext() repeatedly. * * @param length length of output array * @return array of generated values * @throws IOException in REPLAY_MODE if a file I/O error occurs * @throws MathIllegalStateException if mode is not recognized * @throws MathIllegalArgumentException if the underlying random generator thwrows one */ public double[] fill(int length) throws IOException, MathIllegalStateException, MathIllegalArgumentException { double[] out = new double[length]; for (int i = 0; i < length; i++) { out[i] = getNext(); } return out; } /** * Computes the empirical distribution using values from the file * in valuesFileURL, using the default number of bins. *

* valuesFileURL must exist and be * readable by *this at runtime.

*

* This method must be called before using getNext() * with mode = DIGEST_MODE

* * @throws IOException if an I/O error occurs reading the input file * @throws NullArgumentException if the {@code valuesFileURL} has not been set * @throws ZeroException if URL contains no data */ public void computeDistribution() throws IOException, ZeroException, NullArgumentException { computeDistribution(EmpiricalDistribution.DEFAULT_BIN_COUNT); } /** * Computes the empirical distribution using values from the file * in valuesFileURL and binCount bins. *

* valuesFileURL must exist and be readable by this process * at runtime.

*

* This method must be called before using getNext() * with mode = DIGEST_MODE

* * @param binCount the number of bins used in computing the empirical * distribution * @throws NullArgumentException if the {@code valuesFileURL} has not been set * @throws IOException if an error occurs reading the input file * @throws ZeroException if URL contains no data */ public void computeDistribution(int binCount) throws NullArgumentException, IOException, ZeroException { empiricalDistribution = new EmpiricalDistribution(binCount, randomData.getRandomGenerator()); empiricalDistribution.load(valuesFileURL); mu = empiricalDistribution.getSampleStats().getMean(); sigma = empiricalDistribution.getSampleStats().getStandardDeviation(); } /** * Returns the data generation mode. See {@link ValueServer the class javadoc} * for description of the valid values of this property. * * @return Value of property mode. */ public int getMode() { return mode; } /** * Sets the data generation mode. * * @param mode New value of the data generation mode. */ public void setMode(int mode) { this.mode = mode; } /** * Returns the URL for the file used to build the empirical distribution * when using {@link #DIGEST_MODE}. * * @return Values file URL. */ public URL getValuesFileURL() { return valuesFileURL; } /** * Sets the {@link #getValuesFileURL() values file URL} using a string * URL representation. * * @param url String representation for new valuesFileURL. * @throws MalformedURLException if url is not well formed */ public void setValuesFileURL(String url) throws MalformedURLException { this.valuesFileURL = new URL(url); } /** * Sets the the {@link #getValuesFileURL() values file URL}. * *

The values file must be an ASCII text file containing one * valid numeric entry per line.

* * @param url URL of the values file. */ public void setValuesFileURL(URL url) { this.valuesFileURL = url; } /** * Returns the {@link EmpiricalDistribution} used when operating in {@value #DIGEST_MODE}. * * @return EmpircalDistribution built by {@link #computeDistribution()} */ public EmpiricalDistribution getEmpiricalDistribution() { return empiricalDistribution; } /** * Resets REPLAY_MODE file pointer to the beginning of the valuesFileURL. * * @throws IOException if an error occurs opening the file * @throws NullPointerException if the {@code valuesFileURL} has not been set. */ public void resetReplayFile() throws IOException { if (filePointer != null) { try { filePointer.close(); filePointer = null; } catch (IOException ex) { //NOPMD // ignore } } filePointer = new BufferedReader(new InputStreamReader(valuesFileURL.openStream(), "UTF-8")); } /** * Closes {@code valuesFileURL} after use in REPLAY_MODE. * * @throws IOException if an error occurs closing the file */ public void closeReplayFile() throws IOException { if (filePointer != null) { filePointer.close(); filePointer = null; } } /** * Returns the mean used when operating in {@link #GAUSSIAN_MODE}, {@link #EXPONENTIAL_MODE} * or {@link #UNIFORM_MODE}. When operating in {@link #CONSTANT_MODE}, this is the constant * value always returned. Calling {@link #computeDistribution()} sets this value to the * overall mean of the values in the {@link #getValuesFileURL() values file}. * * @return Mean used in data generation. */ public double getMu() { return mu; } /** * Sets the {@link #getMu() mean} used in data generation. Note that calling this method * after {@link #computeDistribution()} has been called will have no effect on data * generated in {@link #DIGEST_MODE}. * * @param mu new Mean value. */ public void setMu(double mu) { this.mu = mu; } /** * Returns the standard deviation used when operating in {@link #GAUSSIAN_MODE}. * Calling {@link #computeDistribution()} sets this value to the overall standard * deviation of the values in the {@link #getValuesFileURL() values file}. This * property has no effect when the data generation mode is not * {@link #GAUSSIAN_MODE}. * * @return Standard deviation used when operating in {@link #GAUSSIAN_MODE}. */ public double getSigma() { return sigma; } /** * Sets the {@link #getSigma() standard deviation} used in {@link #GAUSSIAN_MODE}. * * @param sigma New standard deviation. */ public void setSigma(double sigma) { this.sigma = sigma; } /** * Reseeds the random data generator. * * @param seed Value with which to reseed the {@link RandomDataImpl} * used to generate random data. */ public void reSeed(long seed) { randomData.reSeed(seed); } //------------- private methods --------------------------------- /** * Gets a random value in DIGEST_MODE. *

* Preconditions:

    *
  • Before this method is called, computeDistribution() * must have completed successfully; otherwise an * IllegalStateException will be thrown

* * @return next random value from the empirical distribution digest * @throws MathIllegalStateException if digest has not been initialized */ private double getNextDigest() throws MathIllegalStateException { if ((empiricalDistribution == null) || (empiricalDistribution.getBinStats().size() == 0)) { throw new MathIllegalStateException(LocalizedFormats.DIGEST_NOT_INITIALIZED); } return empiricalDistribution.getNextValue(); } /** * Gets next sequential value from the valuesFileURL. *

* Throws an IOException if the read fails.

*

* This method will open the valuesFileURL if there is no * replay file open.

*

* The valuesFileURL will be closed and reopened to wrap around * from EOF to BOF if EOF is encountered. EOFException (which is a kind of * IOException) may still be thrown if the valuesFileURL is * empty.

* * @return next value from the replay file * @throws IOException if there is a problem reading from the file * @throws MathIllegalStateException if URL contains no data * @throws NumberFormatException if an invalid numeric string is * encountered in the file */ private double getNextReplay() throws IOException, MathIllegalStateException { String str = null; if (filePointer == null) { resetReplayFile(); } if ((str = filePointer.readLine()) == null) { // we have probably reached end of file, wrap around from EOF to BOF closeReplayFile(); resetReplayFile(); if ((str = filePointer.readLine()) == null) { throw new MathIllegalStateException(LocalizedFormats.URL_CONTAINS_NO_DATA, valuesFileURL); } } return Double.parseDouble(str); } /** * Gets a uniformly distributed random value with mean = mu. * * @return random uniform value * @throws MathIllegalArgumentException if the underlying random generator thwrows one */ private double getNextUniform() throws MathIllegalArgumentException { return randomData.nextUniform(0, 2 * mu); } /** * Gets an exponentially distributed random value with mean = mu. * * @return random exponential value * @throws MathIllegalArgumentException if the underlying random generator thwrows one */ private double getNextExponential() throws MathIllegalArgumentException { return randomData.nextExponential(mu); } /** * Gets a Gaussian distributed random value with mean = mu * and standard deviation = sigma. * * @return random Gaussian value * @throws MathIllegalArgumentException if the underlying random generator thwrows one */ private double getNextGaussian() throws MathIllegalArgumentException { return randomData.nextGaussian(mu, sigma); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy