Mark R. Diggory 2003-06-07 01:36:57 +00:00
parent 1999928282
commit a6c324e669
2 changed files with 235 additions and 91 deletions

View File

@ -61,9 +61,11 @@ import java.io.IOException;
import java.net.MalformedURLException;
/**
* Generates values for use in simulation applications.<br>
* Generates values for use in simulation applications.
* <p>
* How values are generated is determined by the <code>mode</code>
* property. <p>
* property.
* <p>
* Supported <code>mode</code> values are: <ul>
* <li> DIGEST_MODE -- uses an empirical distribution </li>
* <li> REPLAY_MODE -- replays data from <code>valuesFile</code></li>
@ -77,7 +79,7 @@ import java.net.MalformedURLException;
* <li> CONSTANT_MODE -- returns <code>mu</code> every time.</li></ul>
*
* @author Phil Steitz
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*
*/
public class ValueServer {
@ -110,13 +112,13 @@ public class ValueServer {
/** Replay data from valuesFilePath */
public static final int REPLAY_MODE = 1;
/** Uniform random variates with mean = mu */
/** Uniform random deviates with mean = mu */
public static final int UNIFORM_MODE = 2;
/** Exponential random variates with mean = mu */
/** Exponential random deviates with mean = mu */
public static final int EXPONENTIAL_MODE = 3;
/** Gaussian random variates with mean = mu, std dev = sigma */
/** Gaussian random deviates with mean = mu, std dev = sigma */
public static final int GAUSSIAN_MODE = 4;
/** Always return mu */
@ -128,10 +130,10 @@ public class ValueServer {
/**
* Returns the next generated value, generated according
* to the mode value (see MODE constants)
* to the mode value (see MODE constants).
*
* @return generated value
* @throws IOException in REPLAY_MODE if file I/O error occurs
* @throws IOException in REPLAY_MODE if a file I/O error occurs
*/
public double getNext() throws IOException {
switch (mode) {
@ -146,8 +148,36 @@ public class ValueServer {
}
}
/**
* 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
*/
public void fill(double[] values) throws IOException {
for (int i = 0; i < values.length; i++) {
values[i] = getNext();
}
}
/**
* Returns an array of length <code>length</code> 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
*/
public double[] fill(int length) throws IOException {
double[] out = new double[length];
for (int i = 0; i < length; i++) {
out[i] = getNext();
}
return out;
}
/**
* Computes the empirical distribution using values from file
* Computes the empirical distribution using values from the file
* in <code>valuesFilePath</code>, using the default number of bins.
* <p>
* <code>valuesFileURL</code> must exist and be
@ -173,90 +203,18 @@ public class ValueServer {
* This method must be called before using <code>getNext()</code>
* with <code>mode = DISGEST_MODE</code>
*
* @param binCount the number of bins used in computing the empirical
* distribution
* @throws IOException if an error occurs reading the input file
*/
public void computeDistribution(int binCount)
throws IOException{
throws IOException {
empiricalDistribution = new EmpiricalDistributionImpl(binCount);
empiricalDistribution.load(valuesFileURL.getFile());
mu = empiricalDistribution.getSampleStats().getMean();
sigma = empiricalDistribution.getSampleStats().getStandardDeviation();
}
/**
* Gets a random value in DIGEST_MODE.
* <p>
* <strong>Preconditions</strong>: <ul>
* <li>Before this method is called, <code>computeDistribution()</code>
* must have completed successfully; otherwise an
* <code>IllegalStateException</code> will be thrown</li></ul>
*
* @return next random value form the empirical distribution digest
*/
private double getNextDigest() {
if ((empiricalDistribution == null) ||
(empiricalDistribution.getBinStats().size() == 0)) {
throw new IllegalStateException("Digest not initialized");
}
return empiricalDistribution.getNextValue();
}
/**
* Gets next sequential value from the <code>valuesFilePath</code>
* opened by <code>openReplayFile()</code>.
* <p>
* Throws an IOException if <code>filePointer</code> is null or read fails.
* Will wrap around to BOF is EOF is encountered.
* <p>
* <strong>Preconditions</strong>: <ul>
* <li> openReplayfile() must have completed successfully before
* invoking this method; otherwise an <code>IlleglaStateException</code>
* will be thrown</li></ul>
*
* @return next value from the replay file
* @throws IOException if there is a problem reading from the file
*/
private double getNextReplay() throws IOException{
String str = null;
if (filePointer == null) {
throw new IllegalStateException("replay file not open");
}
if ((str = filePointer.readLine()) == null) {
closeReplayFile();
openReplayFile();
str = filePointer.readLine();
}
return new Double(str).doubleValue();
}
/**
* Gets a uniformly distributed random value with mean = mu
*
* @return random uniform value
*/
private double getNextUniform() {
return 2.0*mu*Math.random();
}
/**
* Gets an exponentially distributed random value with mean = mu
*
* @return random exponential value
*/
private double getNextExponential() {
return randomData.nextExponential(mu);
}
/**
* Gets a Gaussian distributed random value with mean = mu
* and standard deviation = sigma
*
* @return random Gaussian value
*/
private double getNextGaussian() {
return randomData.nextGaussian(mu,sigma);
}
/** Getter for property mode.
* @return Value of property mode.
*/
@ -279,10 +237,11 @@ public class ValueServer {
}
/** Setter for property valuesFilePath.
* @param valuesFilePath New value of property valuesFilePath.
* @param url New value of property valuesFilePath.
* @throws MalformedURLException if url is not well formed
*/
public void setValuesFileURL(String URL) throws MalformedURLException {
this.valuesFileURL = new URL(URL);
public void setValuesFileURL(String url) throws MalformedURLException {
this.valuesFileURL = new URL(url);
}
/** Getter for property empiricalDistribution.
@ -293,7 +252,7 @@ public class ValueServer {
}
/**
* Opens <code>valuesFilePath</code> to use in REPLAY_MODE
* Opens <code>valuesFilePath</code> to use in REPLAY_MODE.
*
* @throws IOException if an error occurs opening the file
*/
@ -303,14 +262,119 @@ public class ValueServer {
}
/**
* Closes <code>valuesFilePath</code> after use in REPLAY_MODE
* Closes <code>valuesFilePath</code> 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;
}
}
/** Getter for property mu.
* @return Value of property mu.
*/
public double getMu() {
return mu;
}
/** Setter for property mu.
* @param mu New value of property mu.
*/
public void setMu(double mu) {
this.mu = mu;
}
/** Getter for property sigma.
* @return Value of property sigma.
*/
public double getSigma() {
return sigma;
}
/** Setter for property sigma.
* @param sigma New value of property sigma.
*/
public void setSigma(double sigma) {
this.sigma = sigma;
}
//------------- private methods ---------------------------------
/**
* Gets a random value in DIGEST_MODE.
* <p>
* <strong>Preconditions</strong>: <ul>
* <li>Before this method is called, <code>computeDistribution()</code>
* must have completed successfully; otherwise an
* <code>IllegalStateException</code> will be thrown</li></ul>
*
* @return next random value from the empirical distribution digest
*/
private double getNextDigest() {
if ((empiricalDistribution == null) ||
(empiricalDistribution.getBinStats().size() == 0)) {
throw new IllegalStateException("Digest not initialized");
}
return empiricalDistribution.getNextValue();
}
/**
* Gets next sequential value from the <code>valuesFilePath</code>
* opened by <code>openReplayFile()</code>.
* <p>
* Throws an IOException if <code>filePointer</code> is null or read fails.
* Will wrap around to BOF is EOF is encountered.
* <p>
* <strong>Preconditions</strong>: <ul>
* <li> openReplayfile() must have completed successfully before
* invoking this method; otherwise an <code>IlleglaStateException</code>
* will be thrown</li></ul>
*
* @return next value from the replay file
* @throws IOException if there is a problem reading from the file
*/
private double getNextReplay() throws IOException {
String str = null;
if (filePointer == null) {
throw new IllegalStateException("replay file not open");
}
if ((str = filePointer.readLine()) == null) {
closeReplayFile();
openReplayFile();
str = filePointer.readLine();
}
return new Double(str).doubleValue();
}
/**
* Gets a uniformly distributed random value with mean = mu.
*
* @return random uniform value
*/
private double getNextUniform() {
return randomData.nextUniform(0, 2 * mu);
}
/**
* Gets an exponentially distributed random value with mean = mu.
*
* @return random exponential value
*/
private double getNextExponential() {
return randomData.nextExponential(mu);
}
/**
* Gets a Gaussian distributed random value with mean = mu
* and standard deviation = sigma.
*
* @return random Gaussian value
*/
private double getNextGaussian() {
return randomData.nextGaussian(mu, sigma);
}
}

View File

@ -66,7 +66,7 @@ import org.apache.commons.math.stat.UnivariateImpl;
* Test cases for the ValueServer class.
*
* @author Phil Steitz
* @version $Revision: 1.3 $
* @version $Revision: 1.4 $
*/
public final class ValueServerTest extends TestCase {
@ -103,6 +103,8 @@ public final class ValueServerTest extends TestCase {
double next = 0.0;
double tolerance = 0.1;
vs.computeDistribution();
assertTrue("empirical distribution property",
vs.getEmpiricalDistribution() != null);
Univariate stats = new UnivariateImpl();
for (int i = 1; i < 1000; i++) {
next = vs.getNext();
@ -110,7 +112,20 @@ public final class ValueServerTest extends TestCase {
}
assertEquals("mean", 5.069831575018909, stats.getMean(), tolerance);
assertEquals
("std dev", 1.0173699343977738, stats.getStandardDeviation(), tolerance);
("std dev", 1.0173699343977738, stats.getStandardDeviation(),
tolerance);
vs.computeDistribution(500);
stats = new UnivariateImpl();
for (int i = 1; i < 1000; i++) {
next = vs.getNext();
stats.addValue(next);
}
assertEquals("mean", 5.069831575018909, stats.getMean(), tolerance);
assertEquals
("std dev", 1.0173699343977738, stats.getStandardDeviation(),
tolerance);
}
/**
@ -159,5 +174,70 @@ public final class ValueServerTest extends TestCase {
assertEquals(compareValue,firstDataValue,tolerance);
compareValue = vs.getNext();
assertEquals(compareValue,secondDataValue,tolerance);
vs.closeReplayFile();
// make sure no NPE
vs.closeReplayFile();
}
/**
* Test other ValueServer modes
*/
public void testModes() throws Exception {
vs.setMode(ValueServer.CONSTANT_MODE);
vs.setMu(0);
assertEquals("constant mode test",vs.getMu(),vs.getNext(),Double.MIN_VALUE);
vs.setMode(ValueServer.UNIFORM_MODE);
vs.setMu(2);
double val = vs.getNext();
assertTrue(val > 0 && val < 4);
vs.setSigma(1);
vs.setMode(ValueServer.GAUSSIAN_MODE);
val = vs.getNext();
assertTrue("gaussian value close enough to mean",
val < vs.getMu() + 100*vs.getSigma());
vs.setMode(ValueServer.EXPONENTIAL_MODE);
val = vs.getNext();
assertTrue(val > 0);
try {
vs.setMode(1000);
vs.getNext();
fail("bad mode, expecting IllegalStateException");
} catch (IllegalStateException ex) {
;
}
}
/**
* Test fill
*/
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++) {
assertEquals("fill test in place",2,val[i],Double.MIN_VALUE);
}
double v2[] = vs.fill(3);
for (int i = 0; i < 3; i++) {
assertEquals("fill test in place",2,v2[i],Double.MIN_VALUE);
}
}
/**
* Test getters to make Clover happy
*/
public void testProperties() throws Exception {
vs.setMode(ValueServer.CONSTANT_MODE);
assertEquals("mode test",ValueServer.CONSTANT_MODE,vs.getMode());
vs.setValuesFileURL("http://www.apache.org");
String s = vs.getValuesFileURL();
assertEquals("valuesFileURL test","http://www.apache.org",s);
}
}