From 5de3587b86ffc735020c3b06e60c993cfc4e53ab Mon Sep 17 00:00:00 2001
From: Tim O'Brien
Date: Wed, 21 May 2003 14:21:15 +0000
Subject: [PATCH] Commited patch for issue 20112 from Phil Steitz.
EmpiricalDistribution -- represents an empirical probability distribution and
supports generation of data values that are "like" values in an input file
without making any assumptions about the functional form of the probability
distribution that the data come from. This is useful in simulation
applications where historical data about component performance are
available but do not follow standard distributions (or any application that
requires random data generation from an empirical distribution). Also
generates data for grouped frequency histograms based on the input file.
ValueServer -- a wrapper for RandomData and EmpiricalDistribution that
generates values in each of the following modes:
* DIGEST_MODE -- uses an empirical distribution
* REPLAY_MODE -- replays data from an input file
* UNIFORM_MODE -- generates uniformly distributed random values
* EXPONENTIAL_MODE -- generates exponentially distributed random
values
* GAUSSIAN_MODE -- generates Gaussian distributed random values
* CONSTANT_MODE -- returns the same value every time.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/math/trunk@140848 13f79535-47bb-0310-9956-ffa450edef68
---
project.xml | 1 +
.../commons/math/EmpiricalDistribution.java | 180 +++
.../math/EmpiricalDistributionImpl.java | 279 +++++
.../org/apache/commons/math/ValueServer.java | 316 ++++++
.../math/EmpiricalDistributionTest.java | 162 +++
.../apache/commons/math/ValueServerTest.java | 160 +++
src/test/org/apache/commons/math/testData.txt | 1000 +++++++++++++++++
7 files changed, 2098 insertions(+)
create mode 100644 src/java/org/apache/commons/math/EmpiricalDistribution.java
create mode 100644 src/java/org/apache/commons/math/EmpiricalDistributionImpl.java
create mode 100644 src/java/org/apache/commons/math/ValueServer.java
create mode 100644 src/test/org/apache/commons/math/EmpiricalDistributionTest.java
create mode 100644 src/test/org/apache/commons/math/ValueServerTest.java
create mode 100644 src/test/org/apache/commons/math/testData.txt
diff --git a/project.xml b/project.xml
index 9b126549c..f73d297fc 100644
--- a/project.xml
+++ b/project.xml
@@ -74,6 +74,7 @@ The Math project is a library of lightweight, self-contained mathematics and sta
${pom.build.unitTestSourceDirectory}
**/*.xml
+ **/*.txt
diff --git a/src/java/org/apache/commons/math/EmpiricalDistribution.java b/src/java/org/apache/commons/math/EmpiricalDistribution.java
new file mode 100644
index 000000000..b51aa547c
--- /dev/null
+++ b/src/java/org/apache/commons/math/EmpiricalDistribution.java
@@ -0,0 +1,180 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.commons.math;
+
+import java.io.IOException;
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * Represents an
+ * empirical probability distribution -- a probability distribution derived
+ * from observed data without making any assumptions about the functional form
+ * of the population distribution that the data come from.
+ * Implementations of this interface maintain data structures, called
+ * distribution digests, that describe empirical distributions and
+ * support the following operations:
+ * - loading the distribution from a file of observed data values
+ * - saving and re-loading distribution digests to/from "digest files"
+ * - dividing the input data into "bin ranges" and reporting bin frequency
+ * counts (data for histogram)
+ * - reporting univariate statistics describing the full set of data values
+ * as well as the observations within each bin
+ * - generating random values from the distribution
+ *
+ * Applications can use EmpiricalDistribution
implementations to
+ * build grouped frequnecy histograms representing the input data or to
+ * generate random values "like" those in the input file -- i.e., the values
+ * generated will follow the distribution of the values in the file.
+ * @author Phil Steitz
+ * @version $Revision: 1.1 $
+ */
+public interface EmpiricalDistribution {
+
+ /**
+ * Computes the empirical distribution from the input file
+ * @param filePath fully qualified name of a file in the local file system
+ * @throws IOException if an IO error occurs
+ */
+ void load(String filePath) throws IOException;
+
+ /**
+ * Computes the empirical distribution from the input file
+ * @param URL url of the input file
+ * @throws IOException if an IO error occurs
+ */
+ void load(File file) throws IOException;
+
+ /**
+ * Generates a random value from this distribution
+ * Preconditions:
+ * - the distribution must be loaded before invoking this method
+ * @throws IllegalStateException if the distribution has not been loaded
+ */
+ double getNextValue() throws IllegalStateException;
+
+
+ /**
+ * Returns a Univariate describing this distribution
+ * Preconditions:
+ * - the distribution must be loaded before invoking this method
+ * @throws IllegalStateException if the distribution has not been loaded
+ */
+ Univariate getSampleStats();
+
+ /**
+ * Loads a saved distribution from a file.
+ * @param file File reference for a file containing a digested distribution
+ * @throws IOException if an error occurs reading the file
+ */
+ void loadDistribution(File file) throws IOException;
+
+ /**
+ * Loads a saved distribution from a file.
+ * @param filePath fully qualified file path for a file
+ * containing a digested distribution
+ * @throws IOException if an error occurs reading the file
+ */
+ void loadDistribution(String filePath) throws IOException;
+
+ /**
+ * Saves distribution to a file. Overwrites the file if it exists.
+ * Preconditions:
+ * - the distribution must be loaded before invoking this method
+ * @param fully qualified file path for the file to be written
+ * @throws IOException if an error occurs reading the file
+ * @throws IllegalStateException if the distribution has not been loaded
+ */
+ void saveDistribution(String filePath) throws
+ IOException,IllegalStateException;
+
+ /**
+ * Saves distribution to a file. Overwrites the file if it exists.
+ * Preconditions:
+ * - the distribution must be loaded before invoking this method
+ * @param file File reference for the file to be written
+ * @throws IOException if an error occurs reading the file
+ * @throws IllegalStateException if the distribution has not been loaded
+ */
+ void saveDistribution(File file) throws IOException,IllegalStateException;
+
+ /**
+ * property indicating whether or not the distribution has been loaded
+ * @return true if the distribution has been loaded
+ */
+ boolean isLoaded();
+
+ /**
+ * Returns the number of bins
+ * @return the number of bins.
+ */
+ int getBinCount();
+
+ /**
+ * Returns a list of Univariates containing statistics describing the
+ * values in each of the bins. The ArrayList is indexed on the bin number.
+ * @return ArrayList of bin statistics.
+ */
+ ArrayList getBinStats();
+
+ /**
+ * Returns the array of upper bounds for the bins. Bins are:
+ * [min,upperBounds[0]],(upperBounds[0],upperBounds[1]],...,
+ * (upperBounds[binCount-1],max]
+ * @return array of bin upper bounds
+ */
+ double[] getUpperBounds();
+
+}
diff --git a/src/java/org/apache/commons/math/EmpiricalDistributionImpl.java b/src/java/org/apache/commons/math/EmpiricalDistributionImpl.java
new file mode 100644
index 000000000..57d429afe
--- /dev/null
+++ b/src/java/org/apache/commons/math/EmpiricalDistributionImpl.java
@@ -0,0 +1,279 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.commons.math;
+
+import java.util.ArrayList;
+import java.io.Serializable;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Implements EmpiricalDistribution
interface using
+ * what amounts to the
+ *
+ * Variable Kernel Method with Gaussian smoothing:
+ * Digesting the input file
+ *
- Pass the file once to compute min and max.
+ * - Divide the range from min-max into
binCount
"bins."
+ * - Pass the data file again, computing bin counts and univariate
+ * statistics (mean, std dev.) for each of the bins
+ * - Divide the interval (0,1) into subintervals associated with the bins,
+ * with the length of a bin's subinterval proportional to its count.
+ * Generating random values from the distribution
+ * - Generate a uniformly distributed value in (0,1)
+ * - Select the subinterval to which the value belongs.
+ *
- Generate a random Gaussian value with mean = mean of the associated
+ * bin and std dev = std dev of associated bin.
+ *USAGE NOTES:
+ *- The
binCount
is set by default to 1000. A good rule of thumb
+ * is to set the bin count to approximately the length of the input file divided
+ * by 10. See TODO: add reference
+ *- The input file must be a plain text file containing one valid numeric
+ * entry per line.
+ *
+ *
+ * @author Phil Steitz
+ * @version $Revision: 1.1 $
+ */
+public class EmpiricalDistributionImpl implements Serializable,EmpiricalDistribution {
+
+
+ /** List of Univariate objects characterizing the bins */
+ private ArrayList binStats = null;
+
+ /** Sample statistics */
+ Univariate sampleStats = null;
+
+ /** number of bins */
+ private int binCount = 1000;
+
+ /** is the distribution loaded? */
+ private boolean loaded = false;
+
+ /** upper bounds of subintervals in (0,1) "belonging" to the bins */
+ private double[] upperBounds = null;
+
+ /**
+ * Creates a new EmpiricalDistribution with the default bin count
+ */
+ public EmpiricalDistributionImpl() {
+ binStats = new ArrayList();
+ }
+
+ /**
+ * Creates a new EmpiricalDistribution with the specified bin count
+ * @param binCount number of bins
+ */
+ public EmpiricalDistributionImpl(int binCount) {
+ this.binCount = binCount;
+ binStats = new ArrayList();
+ }
+
+
+ public void load(String filePath) throws IOException {
+ File file = new File(filePath);
+ load(file);
+ }
+
+
+ public void load(File file) throws IOException {
+ // Pass the file once to get sample stats
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new FileReader(file));
+ String str = null;
+ double val = 0.0;
+ sampleStats = new UnivariateImpl();
+ while ((str = in.readLine()) != null) {
+ val = new Double(str).doubleValue();
+ sampleStats.addValue(val);
+ }
+ in.close();
+ in = null;
+ } finally {
+ if (in != null) try {in.close();} catch (Exception ex) {};
+ }
+
+ // Load array of bin upper bounds -- evenly spaced from min - max
+ double min = sampleStats.getMin();
+ double max = sampleStats.getMax();
+ double delta = (max - min)/(new Double(binCount)).doubleValue();
+ double[] binUpperBounds = new double[binCount];
+ binUpperBounds[0] = min + delta;
+ for (int i = 1; i< binCount - 1; i++) {
+ binUpperBounds[i] = binUpperBounds[i-1] + delta;
+ }
+ binUpperBounds[binCount -1] = max;
+
+ // Initialize binStats ArrayList
+ if (!binStats.isEmpty()) {
+ binStats.clear();
+ }
+ for (int i = 0; i < binCount; i++) {
+ Univariate stats = new UnivariateImpl();
+ binStats.add(i,stats);
+ }
+
+ // Pass the data again, filling data in binStats Array
+ try {
+ in = new BufferedReader(new FileReader(file));
+ String str = null;
+ double val = 0.0d;
+ while ((str = in.readLine()) != null) {
+ val = new Double(str).doubleValue();
+
+ // Find bin and add value to binStats for the bin
+ boolean found = false;
+ int i = 0;
+ while (!found) {
+ if (i >= binCount) {
+ throw new RuntimeException("bin alignment error");
+ }
+ if (val <= binUpperBounds[i]) {
+ found = true;
+ Univariate stats = (Univariate)binStats.get(i);
+ stats.addValue(val);
+ }
+ i++;
+ }
+ }
+ in.close();
+ in = null;
+ } finally {
+ if (in != null) try {in.close();} catch (Exception ex) {};
+ }
+
+ // Assign upperBounds based on bin counts
+ upperBounds = new double[binCount];
+ upperBounds[0] =
+ (((Univariate)binStats.get(0)).getN())/sampleStats.getN();
+ for (int i = 1; i < binCount-1; i++) {
+ upperBounds[i] = upperBounds[i-1] +
+ (((Univariate)binStats.get(i)).getN())/sampleStats.getN();
+ }
+ upperBounds[binCount-1] = 1.0d;
+
+ loaded = true;
+ }
+
+ /** Generates a random value from this distribution */
+ public double getNextValue() throws IllegalStateException {
+
+ if (!loaded) {
+ throw new IllegalStateException("distribution not loaded");
+ }
+
+ // Start with a uniformly distributed random number in (0,1)
+ double x = Math.random();
+
+ // Use this to select the bin and generate a Gaussian within the bin
+ RandomData rd = new RandomDataImpl();
+ for (int i = 0; i < binCount; i++) {
+ if (x <= upperBounds[i]) {
+ Univariate stats = (Univariate)binStats.get(i);
+ if (stats.getN() > 0.5) { // really mean > 0, but avoid fp error
+ if (stats.getStandardDeviation() > 0) { // more than one obs
+ return rd.nextGaussian
+ (stats.getMean(),stats.getStandardDeviation());
+ } else {
+ return stats.getMean(); // only one obs in bin
+ }
+ }
+ }
+ }
+ throw new RuntimeException("No bin selected");
+ }
+
+ public void loadDistribution(String filePath) throws IOException {
+ throw new UnsupportedOperationException("Not Implemented yet :-(");
+ }
+
+ public void loadDistribution(File file) throws IOException {
+ throw new UnsupportedOperationException("Not Implemented yet :-(");
+ }
+
+ public void saveDistribution(String filePath) throws
+ IOException,IllegalStateException {
+ throw new UnsupportedOperationException("Not Implemented yet :-(");
+ }
+
+ public void saveDistribution(File file) throws
+ IOException,IllegalStateException {
+ throw new UnsupportedOperationException("Not Implemented yet :-(");
+ }
+
+ public Univariate getSampleStats() {
+ return sampleStats;
+ }
+
+ public int getBinCount() {
+ return binCount;
+ }
+
+ public ArrayList getBinStats() {
+ return binStats;
+ }
+
+ public double[] getUpperBounds() {
+ return upperBounds;
+ }
+
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+}
diff --git a/src/java/org/apache/commons/math/ValueServer.java b/src/java/org/apache/commons/math/ValueServer.java
new file mode 100644
index 000000000..00e5a70bb
--- /dev/null
+++ b/src/java/org/apache/commons/math/ValueServer.java
@@ -0,0 +1,316 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+
+package org.apache.commons.math;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.File;
+import java.net.URL;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+/**
+ * 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
valuesFile
+ * - 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.
+ *
+ * @author Phil Steitz
+ * @version $Revision: 1.1 $
+ *
+ */
+public class ValueServer {
+ /** 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 RandomDataImpl randomData = new RandomDataImpl();
+
+ // Data generation modes ======================================
+
+ /** Use empirical distribution */
+ public static final int DIGEST_MODE = 0;
+
+ /** Replay data from valuesFilePath */
+ public static final int REPLAY_MODE = 1;
+
+ /** Uniform random variates with mean = mu */
+ public static final int UNIFORM_MODE = 2;
+
+ /** Exponential random variates with mean = mu */
+ public static final int EXPONENTIAL_MODE = 3;
+
+ /** Gaussian random variates with mean = mu, std dev = sigma */
+ public static final int GAUSSIAN_MODE = 4;
+
+ /** Always return mu */
+ public static final int CONSTANT_MODE = 5;
+
+ /** Creates new ValueServer */
+ public ValueServer() {
+ }
+
+ /**
+ * Returns the next generated value, generated according
+ * to the mode value (see MODE constants)
+ *
+ * @return generated value
+ * @throws IOException in REPLAY_MODE if file I/O error occurs
+ */
+ public double getNext() throws IOException {
+ 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 IllegalStateException
+ ("Bad mode: " + mode);
+ }
+ }
+
+ /**
+ * Computes the empirical distribution using values from file
+ * in valuesFilePath
, 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 = DISGEST_MODE
+ *
+ * @throws IOException if an I/O error occurs reading the input file
+ */
+ public void computeDistribution() throws IOException {
+ empiricalDistribution = new EmpiricalDistributionImpl();
+ empiricalDistribution.load(valuesFileURL.getFile());
+ }
+
+ /**
+ * Computes the empirical distribution using values from the file
+ * in valuesFilePath
and binCount
bins.
+ *
+ * valuesFileURL
must exist and be
+ * readable by *this at runtime.
+ *
+ * This method must be called before using getNext()
+ * with mode = DISGEST_MODE
+ *
+ * @throws IOException if an error occurs reading the input file
+ */
+ public void computeDistribution(int binCount)
+ 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.
+ *
+ * Preconditions:
+ * - Before this method is called,
computeDistribution()
+ * must have completed successfully; otherwise an
+ * IllegalStateException
will be thrown
+ *
+ * @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 valuesFilePath
+ * opened by openReplayFile()
.
+ *
+ * Throws an IOException if filePointer
is null or read fails.
+ * Will wrap around to BOF is EOF is encountered.
+ *
+ * Preconditions:
+ * - openReplayfile() must have completed successfully before
+ * invoking this method; otherwise an
IlleglaStateException
+ * will be thrown
+ *
+ * @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.
+ */
+ public int getMode() {
+ return mode;
+ }
+
+ /** Setter for property mode.
+ * @param mode New value of property mode.
+ */
+ public void setMode(int mode) {
+ this.mode = mode;
+ }
+
+ /** Getter for property valuesFilePath.
+ * @return Value of property valuesFilePath.
+ */
+ public String getValuesFileURL() {
+ return valuesFileURL.toString();
+ }
+
+ /** Setter for property valuesFilePath.
+ * @param valuesFilePath New value of property valuesFilePath.
+ */
+ public void setValuesFileURL(String URL) throws MalformedURLException {
+ this.valuesFileURL = new URL(URL);
+ }
+
+ /** Getter for property empiricalDistribution.
+ * @return Value of property empiricalDistribution.
+ */
+ public EmpiricalDistribution getEmpiricalDistribution() {
+ return empiricalDistribution;
+ }
+
+ /**
+ * Opens valuesFilePath
to use in REPLAY_MODE
+ *
+ * @throws IOException if an error occurs opening the file
+ */
+ public void openReplayFile() throws IOException {
+ filePointer = new BufferedReader(new FileReader
+ (new File(valuesFileURL.getFile())));
+ }
+
+ /**
+ * Closes valuesFilePath
after use in REPLAY_MODE
+ *
+ * @throws IOException if an error occurs closing the file
+ */
+ public void closeReplayFile() throws IOException {
+ if (filePointer != null) {
+ filePointer.close();
+ }
+ }
+
+}
diff --git a/src/test/org/apache/commons/math/EmpiricalDistributionTest.java b/src/test/org/apache/commons/math/EmpiricalDistributionTest.java
new file mode 100644
index 000000000..5cb6035e6
--- /dev/null
+++ b/src/test/org/apache/commons/math/EmpiricalDistributionTest.java
@@ -0,0 +1,162 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+package org.apache.commons.math;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.framework.AssertionFailedError;
+import java.io.File;
+import java.net.URL;
+
+/**
+ * Test cases for the EmpiricalDistribution class
+ *
+ * @author Phil Steitz
+ * @version $Revision: 1.1 $ $Date: 2003/05/21 14:21:15 $
+ */
+
+public final class EmpiricalDistributionTest extends TestCase {
+
+ private EmpiricalDistribution empiricalDistribution = null;
+ private File file = null;
+
+ public EmpiricalDistributionTest(String name) {
+ super(name);
+ }
+
+ public void setUp() {
+ empiricalDistribution = new EmpiricalDistributionImpl(100);
+ URL url = getClass().getResource("testData.txt");
+ file = new File(url.getFile());
+ }
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(EmpiricalDistributionTest.class);
+ suite.setName("EmpiricalDistribution Tests");
+ return suite;
+ }
+
+ /**
+ * Test EmpiricalDistrbution.load() using sample data file.
+ * Check that the sampleCount, mu and sigma match data in
+ * the sample data file.
+ */
+ public void testLoad() throws Exception {
+ empiricalDistribution.load(file);
+ // testData File has 10000 values, with mean ~ 5.0, std dev ~ 1
+ // Make sure that loaded distribution matches this
+ assertEquals(empiricalDistribution.getSampleStats().getN(),1000,10E-7);
+ //TODO: replace with statistical tests
+ assertEquals
+ (empiricalDistribution.getSampleStats().getMean(),
+ 5.069831575018909,10E-7);
+ assertEquals
+ (empiricalDistribution.getSampleStats().getStandardDeviation(),
+ 1.0173699343977738,10E-7);
+ }
+
+ /**
+ * 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.
+ */
+ public void testNext() throws Exception {
+ tstGen(0.1);
+ }
+
+ /**
+ * Make sure exception thrown if digest getNext is attempted
+ * before loading empiricalDistribution.
+ */
+ public void testNexFail() {
+ try {
+ empiricalDistribution.getNextValue();
+ fail("Expecting IllegalStateException");
+ } catch (IllegalStateException ex) {;}
+ }
+
+ /**
+ * Make sure we can handle a grid size that is too fine
+ */
+ public void testGridTooFine() throws Exception {
+ empiricalDistribution = new EmpiricalDistributionImpl(10000);
+ tstGen(0.1);
+ }
+
+ /**
+ * How about too fat?
+ */
+ public void testGridTooFat() throws Exception {
+ empiricalDistribution = new EmpiricalDistributionImpl(1);
+ tstGen(5); // ridiculous tolerance; but ridiculous grid size
+ // really just checking to make sure we do not bomb
+ }
+
+ private void tstGen(double tolerance)throws Exception {
+ empiricalDistribution.load(file);
+ Univariate stats = new UnivariateImpl();
+ for (int i = 1; i < 1000; i++) {
+ stats.addValue(empiricalDistribution.getNextValue());
+ }
+ //TODO: replace these with statistical tests -- refactor as necessary
+ assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
+ assertEquals
+ ("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
+ }
+
+
+
+
+}
diff --git a/src/test/org/apache/commons/math/ValueServerTest.java b/src/test/org/apache/commons/math/ValueServerTest.java
new file mode 100644
index 000000000..046dfe3d7
--- /dev/null
+++ b/src/test/org/apache/commons/math/ValueServerTest.java
@@ -0,0 +1,160 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+package org.apache.commons.math;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.framework.AssertionFailedError;
+import java.net.URL;
+
+/**
+ * Test cases for the ValueServer class.
+ *
+ * @author Phil Steitz
+ * @version $Revision: 1.1 $
+ */
+
+public final class ValueServerTest extends TestCase {
+
+ private ValueServer vs = new ValueServer();
+
+ public ValueServerTest(String name) {
+ super(name);
+ }
+
+ public void setUp() {
+ vs.setMode(ValueServer.DIGEST_MODE);
+ try {
+ URL url = getClass().getResource("testData.txt");
+ vs.setValuesFileURL(url.toExternalForm());
+ } catch (Exception ex) {
+ fail("malformed test URL");
+ }
+ }
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(ValueServerTest.class);
+ suite.setName("ValueServer Tests");
+ return suite;
+ }
+
+
+ /**
+ * 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.
+ */
+ public void testNextDigest() throws Exception{
+ double next = 0.0;
+ double tolerance = 0.1;
+ vs.computeDistribution();
+ Univariate stats = new UnivariateImpl();
+ for (int i = 1; i < 1000; i++) {
+ next = vs.getNext();
+ stats.addValue(next);
+ }
+ assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
+ assertEquals
+ ("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
+ }
+
+ /**
+ * Make sure exception thrown if digest getNext is attempted
+ * before loading empiricalDistribution.
+ */
+ public void testNextDigestFail() throws Exception {
+ try {
+ vs.getNext();
+ fail("Expecting IllegalStateException");
+ } catch (IllegalStateException ex) {;}
+ }
+
+ /**
+ * Make sure exception thrown if nextReplay() is attempted
+ * before opening replay file.
+ */
+ public void testNextReplayFail() throws Exception {
+ try {
+ vs.setMode(ValueServer.REPLAY_MODE);
+ vs.getNext();
+ fail("Expecting IllegalStateException");
+ } catch (IllegalStateException ex) {;}
+ }
+
+ /**
+ * 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.
+ */
+ 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.openReplayFile();
+ compareValue = vs.getNext();
+ assertEquals(compareValue,firstDataValue,tolerance);
+ compareValue = vs.getNext();
+ assertEquals(compareValue,secondDataValue,tolerance);
+ for (int i = 3; i < 1001; i++) {
+ compareValue = vs.getNext();
+ }
+ compareValue = vs.getNext();
+ assertEquals(compareValue,firstDataValue,tolerance);
+ compareValue = vs.getNext();
+ assertEquals(compareValue,secondDataValue,tolerance);
+ }
+}
diff --git a/src/test/org/apache/commons/math/testData.txt b/src/test/org/apache/commons/math/testData.txt
new file mode 100644
index 000000000..4a10132ce
--- /dev/null
+++ b/src/test/org/apache/commons/math/testData.txt
@@ -0,0 +1,1000 @@
+4.038625496201205
+3.6485326248346936
+3.6651209675932845
+5.814896279561131
+5.384126469824717
+5.251190723365563
+4.465213440111648
+4.736608014129308
+5.566383814840726
+3.8872277480629114
+5.246598498086048
+3.7511487364188176
+6.733371385175343
+5.388632419618035
+6.036263402962769
+3.8105605069222905
+5.738599503606028
+4.994552792425298
+2.945504336988336
+4.095314381239862
+5.760924710543879
+3.889753944419315
+3.808861160991701
+5.084302950012555
+6.370292933705698
+5.9615431859588455
+4.8790354385481445
+4.068164663649243
+4.26491661935213
+5.911067976258105
+4.1316140545022115
+4.0479985648577115
+5.560425919351912
+5.7777862258090265
+4.6491664757229145
+5.322284766164775
+3.9643060017297818
+3.3374606422520423
+4.070818520139152
+5.162814971692577
+4.68959876937858
+5.729533112912969
+7.160010937980058
+5.154920628387343
+5.992604820701763
+5.317279162752973
+6.3388993007264
+4.38451874656454
+5.024014917973479
+3.7534872319471946
+5.042363342784924
+5.528064915562473
+4.645749024871185
+2.5572755520373756
+3.953716919712825
+3.479482401208564
+4.676100783445583
+4.602236051449888
+7.136692300563229
+3.2411466558895095
+4.188618724984135
+3.6403999184454445
+3.4104206071160776
+4.807963390662261
+4.039073733966207
+4.201017826594899
+4.381868005163936
+5.0635235098658935
+5.9840760229548735
+4.195400406346137
+5.649256144660377
+4.679088153774095
+4.169683379901892
+5.671299804360453
+6.159089864893807
+5.315685219074694
+6.3327786025390305
+5.57348047674858
+6.124073677151904
+4.599177837977919
+4.792320274522308
+5.670142645005109
+5.479531549270221
+4.7740747976996705
+4.99464290442364
+5.474337090086012
+5.232353744280737
+6.411298157619626
+4.757268066271138
+5.217779158748026
+5.07395379944902
+5.5759984176628965
+4.521182520094989
+5.738026445940142
+4.742204968903384
+4.670762511507285
+4.884925361512115
+3.2573282568729462
+4.548387675110013
+4.337950021352034
+3.7875587274144618
+3.6055586455442974
+7.361861332197413
+4.834945622163155
+6.019473054836964
+4.453304225895349
+3.258695681592217
+5.794572588445252
+3.706438851580378
+6.079300672323756
+4.828008457182361
+5.315261102210712
+3.981847695058188
+4.039767325290114
+5.790863349525503
+5.160671471128728
+4.835236459763434
+4.405281184174698
+6.036293520404953
+5.889067983920324
+4.645514887430352
+4.347244670972515
+6.447181244432997
+6.564267268399325
+5.1013992003059885
+4.123378901103389
+2.7101740954226283
+4.209200680057913
+5.085704888132955
+4.26810090240086
+5.54254381015526
+4.721081268239747
+6.890088385585999
+3.9983110493877954
+5.321006894021748
+4.316867375040024
+3.694764624577479
+5.453875921043777
+3.7798857421649927
+3.7228653199742623
+4.807698651287013
+3.953745662132547
+4.821189486606762
+4.453489509051613
+6.4517275696030225
+4.823034188588044
+4.722822481625316
+5.810689805246644
+2.79248319144007
+4.928162269110059
+4.661918219482871
+4.574123379557206
+5.241478194631993
+5.8345087395944155
+7.024415739565572
+3.5536052565954
+6.095523994939967
+5.714650096778455
+4.846741263282074
+6.002769586957791
+5.982356840660745
+5.045480762532407
+6.461077219605347
+4.806649266171423
+6.350848113862498
+6.402679936682352
+3.8190196431210914
+4.189064677946727
+4.868517260374518
+2.145198341547173
+5.9469461091347
+5.88772432287321
+4.258280909990726
+6.740134075161574
+4.6047650031608445
+3.9273659909763774
+4.291244045368331
+5.183827109845055
+5.696810583954774
+3.608472134466666
+4.169004030425733
+3.9965477474540467
+3.7571221568428017
+5.575534565152322
+5.0764208309825065
+5.3185446180363485
+5.157450995663762
+4.961815558094033
+5.687338919107788
+4.185906295178724
+4.382007991332045
+3.5280961455873676
+4.531506809760329
+4.5870808989545635
+4.1932173503939625
+7.213813469684956
+3.1814836225682908
+4.647297462243001
+5.223975935315364
+5.585001659776854
+5.120918864744974
+5.026571594328509
+6.348097968923147
+6.50023470519147
+5.712556147497515
+5.206026515338916
+5.749621140061565
+3.0714726650374033
+6.576852312067237
+7.873101351668455
+6.565410149266118
+6.42923283018875
+4.576910183319347
+4.891822273316748
+6.059357175219146
+3.5324494806223328
+5.02539429500825
+6.078049839679652
+4.395054417468175
+5.710022806162443
+5.577091376894232
+3.131753802875934
+5.4869998928318
+6.413992453090146
+6.368380820674971
+6.052068461844252
+5.480278219624535
+7.051236227914206
+4.748415087916627
+4.559239556696287
+4.780665068784505
+5.349223485326002
+4.522305152002386
+5.678473361027541
+6.734219964637535
+6.713281662687456
+6.22214905332774
+5.716102543806569
+6.336616632829493
+4.8399311234283635
+5.811391244308217
+4.3965755331585905
+5.297963707368242
+5.021726117260926
+4.497125082388555
+4.735667209277485
+6.048804114181307
+4.264048138073914
+7.181013762432201
+4.781684059171574
+5.779533272721499
+4.164421460389599
+3.6986809242837757
+4.8415576143236185
+4.924528568365373
+4.758045335351253
+5.628351489493518
+5.7967639104855415
+4.491988822693669
+2.776750089391839
+4.704679957076673
+4.039607278211126
+5.660350110077993
+4.955611684289963
+3.0641653090331107
+4.896101875253389
+3.6528358436331603
+5.552472713484715
+4.857203367367906
+6.698826102960048
+4.485176970803183
+3.359916665137426
+4.036570806638963
+3.48793689188148
+4.19214761961293
+3.9792199677002866
+6.760873252923419
+4.333561067615548
+5.018626873497648
+3.377671327382937
+4.426183834007672
+8.806961710969402
+5.2068790380550265
+5.483008251803699
+4.287267636533901
+5.931330465014387
+5.257260104496106
+4.623908313559696
+4.365112456604631
+5.600514050451817
+6.184093404453588
+4.9116883675838485
+6.019780977080248
+7.485280872899538
+3.5982660410679284
+4.232210941334369
+5.446496617538108
+6.487976163896015
+3.3960660696641156
+4.733884295853101
+5.352545256764909
+4.107747627715545
+3.949506252011129
+5.017847997679714
+4.24906287118262
+6.720303792581198
+5.832137142236708
+5.010377506040941
+6.458070081692352
+6.501223021355141
+4.612768564431788
+3.801740464538825
+4.469721893125596
+5.061713024524103
+6.872685648715577
+6.145993249521355
+4.638532388190405
+4.70471535512485
+6.417576222531886
+4.118577249932789
+4.431328683019108
+4.747884983644578
+4.495605382683923
+3.5972439735401767
+5.210796056817244
+2.9160129894156026
+3.4596190721900797
+3.972452277026154
+5.5237190584690214
+6.104711796147512
+4.787324556447702
+4.548676032231089
+6.356843891618192
+3.6148998030697816
+4.760679260180754
+4.698041709266617
+4.244003753086054
+5.595546833817678
+3.2784025595193267
+5.326657347561453
+6.213858447402109
+5.213011705084566
+7.232075882741927
+4.806572191866972
+4.680144670146755
+3.946663831660007
+3.6143084085883554
+7.789315918667734
+7.099181638561095
+3.672742516732736
+5.953845998789752
+6.28847712720666
+6.946689084108734
+6.325454389782429
+4.334133006331358
+3.039424552213366
+4.847328734611504
+4.249781519880862
+6.126424188695286
+3.3823135936253257
+6.3280255743100025
+6.150431997847958
+5.4226742397784005
+5.94864601826791
+4.425906835511732
+4.897545227095195
+6.26027333638832
+3.647858418615367
+5.276322437292433
+4.176876069581277
+4.346107259567459
+3.1384418250329995
+4.212957347421948
+4.637757894698186
+6.535589923573854
+5.193072556110316
+5.017309492685374
+5.1750466093509
+4.6381038872450375
+6.071604634493695
+4.357240286904764
+5.122391923621759
+6.556903940099011
+3.8006848201076036
+4.522363890394659
+6.2456602471550635
+5.829300589393535
+4.452647643620209
+5.371890862621703
+4.948677662633424
+5.661113800822228
+5.773629402623548
+6.139823333391851
+6.093004328053013
+5.362399773949667
+6.915042845179306
+5.394739321037944
+5.141451574018252
+5.053294383161769
+4.9834920876470665
+6.812746808763125
+3.5705971688428266
+4.664119854301202
+6.310596552569324
+5.674835228932813
+3.4639740645984807
+4.788956793299906
+5.1005488900135845
+4.534989910256703
+3.931742089464332
+3.572625977535623
+5.374511045697475
+3.859408179493194
+5.767053789854141
+5.1414168750827285
+4.7490168496463525
+7.481142748403815
+4.5189492261011575
+5.40235395980428
+6.700234279658992
+3.5063554778412183
+3.9690452319798735
+3.00630763890251
+7.23611608840341
+5.018006325958164
+4.523410620276403
+4.076684362167451
+5.916234395538267
+7.047286572236027
+3.8682363461132017
+4.390658924201581
+4.5292330092964255
+5.07906584568947
+4.671213490610071
+4.095193931403399
+4.054590162572947
+3.2227278245030027
+6.132646335444107
+2.8407359953623814
+4.7279370282096655
+5.593872406613741
+3.382542536766184
+5.85844025043303
+6.461000354065181
+3.4994741020969773
+4.132683344034104
+5.647894883473891
+5.011301190267978
+4.401435886120444
+3.3496957519609927
+6.119687677370172
+4.644762759286699
+4.5205629205178735
+3.0320051244977195
+4.596487037061894
+5.14520534308978
+5.282269168918912
+5.761372455401502
+4.148416743583162
+6.372742039103559
+5.649143130777574
+5.084494528193606
+4.811163551671385
+3.9806520282362476
+4.411511792047385
+4.670987670787611
+5.768451736319585
+3.984558689428816
+5.3293696591099975
+5.413539058295544
+6.40970782426591
+5.481145473625602
+4.36515208836978
+5.161811987273001
+3.963554978392394
+5.098946908474979
+7.786683053797615
+4.927631219070586
+5.524180021898693
+4.523736107490982
+3.557364094609177
+6.128701594561169
+4.2509207146594115
+3.944944115965259
+4.966138264389299
+5.394430219583224
+6.77531735530901
+4.128069102169693
+5.2683457909620355
+3.8872836447608496
+4.486696800422189
+6.5335585640393825
+4.916400608546338
+4.270979919569207
+4.311416898242187
+4.498167295277512
+6.132808180917634
+5.1041291367018875
+5.498388642491546
+5.584526454067219
+6.142894025331306
+4.944671156061267
+4.1686843376349945
+4.818977261651865
+6.235820918635881
+3.3212806573760028
+5.68435151611855
+6.189749316228399
+3.591267557367338
+5.043902793214377
+7.818905185451641
+4.768708643560666
+5.669288800286096
+6.398657810380692
+5.3717200778027605
+5.2573487416126525
+4.822935237131512
+6.182572962936934
+5.6072955002277105
+3.9675191626756288
+6.350858167126948
+6.283995295688788
+4.445782391191543
+6.877548745307459
+5.3208290700871315
+6.09847688940267
+6.434994026138841
+4.32779758193763
+7.2924037238697
+5.419935895280957
+4.288818201810987
+7.242433265647824
+4.947890367713541
+5.916218606455959
+6.490437527083841
+4.617582424838291
+7.957708355752131
+4.879357620439287
+6.103294400805588
+5.639488259504568
+4.335236791293937
+5.202542624850618
+5.4406339076225505
+5.782530244910674
+4.055314639567904
+5.552293301411749
+5.290496801505254
+4.022580394801182
+4.625571974654451
+5.5086593656510825
+4.913637297182931
+4.906396844626936
+6.439485089212817
+5.7942799739945325
+7.158136207286507
+4.280431104751667
+3.9206066719991517
+5.127791240556268
+6.70098532482022
+4.657147097255419
+4.524267698037553
+4.647534545829241
+4.839690189371444
+6.798322548455047
+5.094754599613737
+5.916399329150566
+5.767837713902285
+5.294550523894544
+4.161295164684424
+5.233358678928891
+5.546871474458429
+4.897048191655597
+3.939430251326603
+5.005888208270397
+3.2926576330038655
+4.0159694347757835
+5.056229917378723
+6.568879235955665
+4.497327615853924
+4.690014685240942
+4.746884105330737
+4.841384111334085
+4.14796180246966
+5.461902744235217
+5.869304766250897
+3.52354738655413
+5.582741221891035
+4.997825621424692
+5.439611672191855
+4.819402835865619
+5.76136287301575
+6.143090288547951
+5.976125217642891
+6.157007787875113
+4.912778652906766
+6.540414953620538
+3.8210262932626495
+4.727149320768898
+4.955255599543759
+5.7983414047818265
+5.167409288825197
+5.059246623397723
+6.965380962189423
+5.531311904089661
+5.4022568784996885
+4.344352255655229
+5.745261070226892
+5.118820012265567
+4.960430609470355
+4.487905086804239
+3.8537512154805835
+4.839114062528739
+5.367538410451759
+6.202050661574205
+4.001800559371117
+6.119617239220475
+3.236283913097008
+5.610134770285298
+5.757041556538514
+4.083399027093518
+5.055588718117847
+4.580930359877383
+6.545516697552579
+5.916270431823864
+3.761559453909257
+6.037777237143994
+7.29718541816528
+4.8965176227762734
+3.941358569293476
+3.9289815988008847
+3.2604315357316436
+4.639329221347256
+6.570997662310685
+3.851958625190621
+5.859087244914328
+4.647365626452129
+6.076778087850363
+4.627936340272149
+4.422345848512504
+6.2183675417422
+5.243889853389288
+5.90909311946919
+6.09260484846961
+6.0271781583360475
+6.913810502971691
+5.285845705409185
+5.318460367681083
+5.179580543035928
+4.6834977896331615
+5.382546996207003
+4.606307320228796
+4.038858683454586
+6.271279252908354
+6.0668723017439365
+5.713564644555386
+5.144428649779485
+5.2496039700779615
+3.8392027391676207
+4.7050632415088876
+7.137275712725372
+4.208879180827962
+4.81480733241727
+4.699941077536472
+4.423440083005291
+5.742161495602944
+4.592506326637019
+6.224046541049566
+4.611093653533141
+6.1166037746546165
+5.904004955760586
+5.589433336321981
+4.57489510266225
+5.500028469975376
+4.382479722617695
+4.257470376496386
+6.373209588018213
+5.375461447759072
+2.8662337475774584
+4.699832117278568
+3.102810935311515
+6.501460955698313
+4.550333534073201
+7.944860661426514
+5.69020177364993
+4.006199611798767
+5.11813341012065
+4.896479097282944
+4.816212778128475
+4.940296064591277
+5.419056166663748
+3.4659391357743616
+7.246324501631043
+5.907112751874067
+5.614502217435809
+4.750614593197476
+7.0951293897280205
+4.3819944682346055
+4.958360318480322
+4.962367933857186
+5.715499159595656
+5.220101872658552
+6.088622700649866
+5.491586360474799
+4.656477235994459
+3.8695533953710326
+3.7143742249025538
+3.7411936672155304
+6.603415889834424
+5.62928670505705
+5.5959396553858785
+5.6577330557176095
+6.003846653929077
+4.508563176717718
+5.549881486113916
+4.953305865372426
+6.203554032873964
+5.612208234244517
+4.854464793588011
+5.263585016371758
+3.897600440182904
+5.981235398882815
+5.531277293213279
+4.8817070690071445
+3.712544699529063
+3.513432242611217
+5.006035295792077
+7.124520658535316
+3.4782033127607037
+4.829578059223972
+5.742892584711905
+4.361333503197903
+4.601687049512891
+6.035189727259647
+4.711273209758127
+4.272043208125593
+4.447702393976457
+5.17487393756583
+4.741015989802225
+4.953808452791662
+4.6645084492292765
+4.276788530554644
+7.325515154525428
+4.602597440231014
+5.082884146093998
+3.068409439905545
+4.809983425115099
+3.8747882947708083
+4.893233436073575
+5.376932606908371
+6.239910432522629
+6.041695571547008
+5.317735375674715
+5.160517819092331
+5.283748111202239
+6.5357867130743745
+5.537247902605441
+5.4185896683530235
+5.287616337544387
+5.981700012459223
+5.992385624329782
+5.758772999982491
+4.599744432168506
+5.7237660286844605
+2.5862937961454855
+4.319918124665613
+7.566860260437548
+3.202784785619934
+6.67642720284947
+5.215802050091852
+5.452814592454087
+4.192858032386887
+5.299199379721475
+3.291677765243241
+4.632695766333648
+5.115714853147839
+4.996260485718097
+3.5271286032511773
+4.659715887897552
+6.587392147323261
+5.989132075359954
+3.8378063660060056
+4.975951043892332
+3.90853196371359
+5.708783809093124
+6.591895462100242
+5.653528117636727
+3.665428787393319
+4.324537690925271
+6.234413976864244
+4.053504794002944
+5.713371183460703
+4.670243561862966
+3.352660528859447
+4.020147292531281
+5.121933145078237
+4.282377411958472
+4.088770874857499
+4.275716553910016
+4.284046155337823
+6.449567142111275
+3.3275914286077084
+4.837717853228399
+5.261182985672333
+6.073443097165901
+5.40483608136289
+4.690566013556853
+4.222184746341714
+5.790245443382679
+5.020060832906476
+5.576527321711127
+5.340393035828579
+5.301460661931292
+5.076040366457228
+6.296482877500045
+3.037720796600903
+6.321850760102656
+5.701339165316606
+4.991940459105436
+5.758970102557518
+4.322111367356909
+5.721255109646473
+5.511881303620453
+4.9563635195228954
+6.861001584068987
+3.8299029968884195
+4.322974731453332
+5.3047403550360634
+6.0756269754391825
+6.117153630436378
+4.5085862451026495
+4.832132638553977
+4.699215334058029
+7.982648077178181
+3.303778194960711
+6.845166964779691
+5.175136241842978
+5.611538016661082
+4.293354218279116
+6.2617605857039775
+4.646868778200023
+5.596211970851805
+6.4731028962866635
+5.9737535333484795
+6.411386536458501
+2.7695062051965302
+3.5560570906765894
+5.451690061978083
+6.503535887841675
+4.695530301460264
+4.706120568510652
+2.800841111510871
+5.364729318170148
+5.1911558656154835
+5.947415408072919
+4.777513714112934
+4.596459418828304
+5.043317097051506
+5.174749896541634
+5.258257882159918
+3.887023257269741
+5.131383317673293
+5.843231353166214
+6.472487193651527
+5.763704927517821
+6.024396779444038
+4.926879229092987
+6.558645082464584
+5.447575064546803
+4.286751335276036
+3.9071252303818644
+4.618489035299945
+5.088217807208579
+3.808752600228301
+5.861810119867259
+4.033532296400091
+5.74542761207288
+4.925806147050348
+3.679404591586196
+4.05604604887352
+5.87881882930846
+4.513573760688276
+4.915009783906388
+3.654483449601882
+4.912095784340134
+3.3774256594506396
+4.188548007093734
+5.4860540834510445
+4.483111427918742
+6.091604204270534
+4.913639044459108
+6.347957296069254
+5.777137740280461
+4.996625717628335
+3.357832000765961
+4.529640780144531
+6.655383658310578
+5.187418414545693
+5.275067584707507
+5.50723064248028
+4.636201988408981
+4.947416066568987
+7.027581910469225
+4.570962245627946
+5.947355941474328
+4.7057667163042245
+4.786943520378938
+5.615852784022176
+4.645129057815488
+5.263882354785195
+3.844951724466573
+5.554260404852657
+4.684091248268045
+5.13336102667963
+3.417837773686996
+4.392489033666552
+6.270027300253521
+6.102372796945901
+4.219653651099504
+5.076173402237902
+4.383422445264855
+3.0437995085361025
+5.377941796580727
+6.276975902314367
+4.315133675763909
+5.507204150696545
+4.886780791403244
+7.147240935203286
+3.900457465197911
+5.102470142455588
+7.084247234995372
+5.457300111792919
+4.60867925423519
+6.2840312118540815
+7.236947706509271
+7.133509547170027
+4.3015318378968
+5.043756433592529
+5.108881706267525
+5.5240023845728645
+5.858632364389344
+5.981971317600007
+6.259948473084726
+4.062783955426871
+5.218852203995356
+3.8038254404258813
+4.758585778361602
+4.376196481713867
+4.458880802424765
+3.96326498727664
+3.6778134622710104
+4.374934998721925
+7.489468914416122
+5.700987063590436
+3.3100952240676955
+5.1696122166092415
+6.541584919841012
+4.4595571152023465
+4.366611842258099
+5.382259676070623
+4.7794428978336825
+3.757838857759169
+6.545307984939696
+4.881890171568036
+5.7063933726311165
+4.7730257133517116
+3.873677842944983
+3.840259191338565
+4.593661080441791
+4.511107632929962
+5.5385052402039605
+5.441167937479936
+5.984890322415174
+5.403820054129332
+5.148546201719365
+4.838476271562129
+6.2440438844133075
+3.9741885421050913
+6.327490860577795
+4.633940514497735
+5.232122748521683
+4.456999940494487
+5.576626928088951
+3.2818610857426584
+5.134684374559793
+4.602466559265273
+5.891324885962796
+5.517816321593768
+6.624687761337339
+5.2683180340267874
+4.662418552035468
+4.622236368091395
+5.536060664096081
+3.272870360657461
+3.9899131914173696
+5.121549579739896
+5.928806028927443
+4.259133981719825
+5.313734011651727
+5.635277610987355
+4.524627655490917