From e4914557372fc1c166a34027d79c94e054b3ed9e Mon Sep 17 00:00:00 2001 From: Gilles Date: Thu, 19 May 2016 18:32:08 +0200 Subject: [PATCH] MATH-1346 Class removed: similar functionality is available from "EmpiricalDistribution", "RandomUtils.DataGenerator" and classes in package "o.a.c.m.distribution". --- .../commons/math4/random/ValueServer.java | 445 ------------------ .../commons/math4/random/ValueServerTest.java | 242 ---------- 2 files changed, 687 deletions(-) delete mode 100644 src/main/java/org/apache/commons/math4/random/ValueServer.java delete mode 100644 src/test/java/org/apache/commons/math4/random/ValueServerTest.java diff --git a/src/main/java/org/apache/commons/math4/random/ValueServer.java b/src/main/java/org/apache/commons/math4/random/ValueServer.java deleted file mode 100644 index 9e32035e7..000000000 --- a/src/main/java/org/apache/commons/math4/random/ValueServer.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * 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.math4.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.math4.exception.MathIllegalArgumentException; -import org.apache.commons.math4.exception.MathIllegalStateException; -import org.apache.commons.math4.exception.NullArgumentException; -import org.apache.commons.math4.exception.ZeroException; -import org.apache.commons.math4.exception.util.LocalizedFormats; - -/** - * Generates values for use in simulation applications. - *

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

- *

- * Supported mode values are:

- * - * - */ -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 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); - 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 RandomDataGenerator} - * used to generate random data. - */ - public void reSeed(long seed) { - randomData.reSeed(seed); - } - - //------------- private methods --------------------------------- - - /** - * Gets a random value in DIGEST_MODE. - *

- * Preconditions:

- * - * @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.createSampler(randomData.getRandomProvider()).sample(); - } - - /** - * 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); - } - -} diff --git a/src/test/java/org/apache/commons/math4/random/ValueServerTest.java b/src/test/java/org/apache/commons/math4/random/ValueServerTest.java deleted file mode 100644 index f9c63efc1..000000000 --- a/src/test/java/org/apache/commons/math4/random/ValueServerTest.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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.math4.random; - -import java.net.URL; -import java.util.Arrays; - -import org.apache.commons.math4.RetryRunner; -import org.apache.commons.math4.exception.MathIllegalStateException; -import org.apache.commons.math4.exception.ZeroException; -import org.apache.commons.math4.random.ValueServer; -import org.apache.commons.math4.random.Well19937c; -import org.apache.commons.math4.stat.descriptive.SummaryStatistics; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test cases for the ValueServer class. - * - */ - -@RunWith(RetryRunner.class) -public final class ValueServerTest { - - private final ValueServer vs = new ValueServer(new Well19937c(100)); - - @Before - public void setUp() { - vs.setMode(ValueServer.DIGEST_MODE); - URL url = getClass().getResource("testData.txt"); - vs.setValuesFileURL(url); - } - - /** - * Generate 1000 random values and make sure they look OK.
- * Note that there is a non-zero (but very small) probability that - * these tests will fail even if the code is working as designed. - */ - @Test - public void testNextDigest() throws Exception { - double next = 0.0; - double tolerance = 0.1; - vs.computeDistribution(); - Assert.assertTrue("empirical distribution property", - vs.getEmpiricalDistribution() != null); - SummaryStatistics stats = new SummaryStatistics(); - for (int i = 1; i < 1000; i++) { - next = vs.getNext(); - stats.addValue(next); - } - Assert.assertEquals("mean", 5.069831575018909, stats.getMean(), tolerance); - Assert.assertEquals("std dev", 1.0173699343977738, stats.getStandardDeviation(), - tolerance); - - vs.computeDistribution(500); - stats = new SummaryStatistics(); - for (int i = 1; i < 1000; i++) { - next = vs.getNext(); - stats.addValue(next); - } - Assert.assertEquals("mean", 5.069831575018909, stats.getMean(), tolerance); - Assert.assertEquals("std dev", 1.0173699343977738, stats.getStandardDeviation(), - tolerance); - } - - /** - * Verify that when provided with fixed seeds, stochastic modes - * generate fixed sequences. Verifies the fix for MATH-654. - */ - @Test - public void testFixedSeed() throws Exception { - ValueServer valueServer = new ValueServer(); - URL url = getClass().getResource("testData.txt"); - valueServer.setValuesFileURL(url); - valueServer.computeDistribution(); - checkFixedSeed(valueServer, ValueServer.DIGEST_MODE); - checkFixedSeed(valueServer, ValueServer.EXPONENTIAL_MODE); - checkFixedSeed(valueServer, ValueServer.GAUSSIAN_MODE); - checkFixedSeed(valueServer, ValueServer.UNIFORM_MODE); - } - - /** - * Do the check for {@link #testFixedSeed()} - * @param mode ValueServer mode - */ - private void checkFixedSeed(ValueServer valueServer, int mode) throws Exception { - valueServer.reSeed(1000); - valueServer.setMode(mode); - double[][] values = new double[2][100]; - for (int i = 0; i < 100; i++) { - values[0][i] = valueServer.getNext(); - } - valueServer.reSeed(1000); - for (int i = 0; i < 100; i++) { - values[1][i] = valueServer.getNext(); - } - Assert.assertTrue(Arrays.equals(values[0], values[1])); - } - - /** - * Make sure exception thrown if digest getNext is attempted - * before loading empiricalDistribution. - */ - @Test - public void testNextDigestFail() throws Exception { - try { - vs.getNext(); - Assert.fail("Expecting MathIllegalStateException"); - } catch (MathIllegalStateException ex) {} - } - - @Test - public void testEmptyReplayFile() throws Exception { - try { - URL url = getClass().getResource("emptyFile.txt"); - vs.setMode(ValueServer.REPLAY_MODE); - vs.setValuesFileURL(url); - vs.getNext(); - Assert.fail("an exception should have been thrown"); - } catch (MathIllegalStateException mise) { - // expected behavior - } - } - - @Test - public void testEmptyDigestFile() throws Exception { - try { - URL url = getClass().getResource("emptyFile.txt"); - vs.setMode(ValueServer.DIGEST_MODE); - vs.setValuesFileURL(url); - vs.computeDistribution(); - Assert.fail("an exception should have been thrown"); - } catch (ZeroException ze) { - // expected behavior - } - } - - /** - * Test ValueServer REPLAY_MODE using values in testData file.
- * Check that the values 1,2,1001,1002 match data file values 1 and 2. - * the sample data file. - */ - @Test - public void testReplay() throws Exception { - double firstDataValue = 4.038625496201205; - double secondDataValue = 3.6485326248346936; - double tolerance = 10E-15; - double compareValue = 0.0d; - vs.setMode(ValueServer.REPLAY_MODE); - vs.resetReplayFile(); - compareValue = vs.getNext(); - Assert.assertEquals(compareValue,firstDataValue,tolerance); - compareValue = vs.getNext(); - Assert.assertEquals(compareValue,secondDataValue,tolerance); - for (int i = 3; i < 1001; i++) { - compareValue = vs.getNext(); - } - compareValue = vs.getNext(); - Assert.assertEquals(compareValue,firstDataValue,tolerance); - compareValue = vs.getNext(); - Assert.assertEquals(compareValue,secondDataValue,tolerance); - vs.closeReplayFile(); - // make sure no NPE - vs.closeReplayFile(); - } - - /** - * Test other ValueServer modes - */ - @Test - public void testModes() throws Exception { - vs.setMode(ValueServer.CONSTANT_MODE); - vs.setMu(0); - Assert.assertEquals("constant mode test",vs.getMu(),vs.getNext(),Double.MIN_VALUE); - vs.setMode(ValueServer.UNIFORM_MODE); - vs.setMu(2); - double val = vs.getNext(); - Assert.assertTrue(val > 0 && val < 4); - vs.setSigma(1); - vs.setMode(ValueServer.GAUSSIAN_MODE); - val = vs.getNext(); - Assert.assertTrue("gaussian value close enough to mean", - val < vs.getMu() + 100*vs.getSigma()); - vs.setMode(ValueServer.EXPONENTIAL_MODE); - val = vs.getNext(); - Assert.assertTrue(val > 0); - try { - vs.setMode(1000); - vs.getNext(); - Assert.fail("bad mode, expecting MathIllegalStateException"); - } catch (MathIllegalStateException ex) { - // ignored - } - } - - /** - * Test fill - */ - @Test - public void testFill() throws Exception { - vs.setMode(ValueServer.CONSTANT_MODE); - vs.setMu(2); - double[] val = new double[5]; - vs.fill(val); - for (int i = 0; i < 5; i++) { - Assert.assertEquals("fill test in place",2,val[i],Double.MIN_VALUE); - } - double v2[] = vs.fill(3); - for (int i = 0; i < 3; i++) { - Assert.assertEquals("fill test in place",2,v2[i],Double.MIN_VALUE); - } - } - - /** - * Test getters to make Clover happy - */ - @Test - public void testProperties() throws Exception { - vs.setMode(ValueServer.CONSTANT_MODE); - Assert.assertEquals("mode test",ValueServer.CONSTANT_MODE,vs.getMode()); - vs.setValuesFileURL("http://www.apache.org"); - URL url = vs.getValuesFileURL(); - Assert.assertEquals("valuesFileURL test","http://www.apache.org",url.toString()); - } - -}