diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..e0f15db
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "automatic"
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 15cf713..70a86c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,4 +13,18 @@
23
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.2.0
+ test
+
+
+ org.junit.platform
+ junit-platform-runner
+ 1.2.0
+ test
+
+
\ No newline at end of file
diff --git a/src/main/java/net/berack/upo/valpre/rand/Distribution.java b/src/main/java/net/berack/upo/valpre/rand/Distribution.java
index 82310c3..4d06cda 100644
--- a/src/main/java/net/berack/upo/valpre/rand/Distribution.java
+++ b/src/main/java/net/berack/upo/valpre/rand/Distribution.java
@@ -10,7 +10,7 @@ public interface Distribution {
* Represents an exponential distribution.
*/
public static class Exponential implements Distribution {
- private final double lambda;
+ public final double lambda;
/**
* Creates a new exponential distribution with the given rate.
@@ -31,8 +31,8 @@ public interface Distribution {
* Represents a normal distribution.
*/
public static class Normal implements Distribution {
- private final double mean;
- private final double sigma;
+ public final double mean;
+ public final double sigma;
/**
* Creates a new normal distribution with the given mean and standard deviation.
@@ -56,8 +56,8 @@ public interface Distribution {
* Represents a normal distribution using the Box-Muller transform.
*/
public static class NormalBoxMuller implements Distribution {
- private final double mean;
- private final double sigma;
+ public final double mean;
+ public final double sigma;
/**
* Creates a new normal distribution with the given mean and standard deviation.
@@ -74,9 +74,102 @@ public interface Distribution {
public double sample(Rng rng) {
var sample1 = rng.random();
var sample2 = rng.random();
- //remove the other value for thread safety
- //next = mean + sigma * Math.sqrt(-2 * Math.log(sample1)) * Math.sin(2 * Math.PI * sample2);
+ // remove the other value for thread safety
+ // next = mean + sigma * Math.sqrt(-2 * Math.log(sample1)) * Math.sin(2 *
+ // Math.PI * sample2);
return mean + sigma * Math.sqrt(-2 * Math.log(sample1)) * Math.cos(2 * Math.PI * sample2);
}
}
+
+ /**
+ * Represent a uniform distribution.
+ */
+ public static class Uniform implements Distribution {
+ public final double min;
+ public final double max;
+
+ /**
+ * Creates a new uniform distribution with the given min value and max value.
+ *
+ * @param min the minimum value possible
+ * @param max the maximum value possible
+ */
+ public Uniform(double min, double max) {
+ this.min = min;
+ this.max = max;
+ }
+
+ @Override
+ public double sample(Rng rng) {
+ return min + rng.random() * (max - min);
+ }
+ }
+
+ /**
+ * Represent an Erlang distribution.
+ */
+ public static class Erlang implements Distribution {
+ public final int k;
+ public final double lambda;
+
+ /**
+ * Creates a new erlang distribution with the given K exponentials, all with the
+ * same lambda.
+ *
+ * @param k the number of exponentials
+ * @param lambda the lambda of the exponentials
+ */
+ public Erlang(int k, double lambda) {
+ this.k = k;
+ this.lambda = lambda;
+ }
+
+ @Override
+ public double sample(Rng rng) {
+ var product = 1.0;
+ for (int i = 0; i < this.k; i++) {
+ product *= rng.random();
+ }
+ return -Math.log(product) / this.lambda;
+ }
+ }
+
+ /**
+ * Represent a HyperExponential distribution.
+ */
+ public static class HyperExponential implements Distribution {
+ private final double[] lambdas;
+ private final double[] probabilities;
+
+ /**
+ * Creates a new hyperexponential distribution with the given lambdas and their
+ * corresponding probabilities.
+ *
+ * @param lambdas the array of lambda values for the exponential
+ * distributions
+ * @param probabilities the array of probabilities for each lambda
+ */
+ public HyperExponential(double[] lambdas, double[] probabilities) {
+ if (lambdas.length != probabilities.length) {
+ throw new IllegalArgumentException("Lambdas and probabilities must have the same length");
+ }
+ this.lambdas = lambdas;
+ this.probabilities = probabilities;
+ }
+
+ @Override
+ public double sample(Rng rng) {
+ var randomValue = rng.random();
+ var i = 0;
+
+ while (i < probabilities.length) {
+ randomValue -= probabilities[i];
+ if (randomValue <= 0.0d)
+ break;
+ i += 1;
+ }
+
+ return -Math.log(rng.random()) / lambdas[i];
+ }
+ }
}
diff --git a/src/main/java/net/berack/upo/valpre/sim/stats/Statistics.java b/src/main/java/net/berack/upo/valpre/sim/stats/Statistics.java
index 34bde62..b800c81 100644
--- a/src/main/java/net/berack/upo/valpre/sim/stats/Statistics.java
+++ b/src/main/java/net/berack/upo/valpre/sim/stats/Statistics.java
@@ -88,7 +88,7 @@ public class Statistics {
}
/**
- * TODO
+ *
*
* @param save
* @param val1
diff --git a/src/test/java/net/berack/upo/valpre/rand/TestRandom.java b/src/test/java/net/berack/upo/valpre/rand/TestRandom.java
new file mode 100644
index 0000000..3d5449c
--- /dev/null
+++ b/src/test/java/net/berack/upo/valpre/rand/TestRandom.java
@@ -0,0 +1,29 @@
+package net.berack.upo.valpre.rand;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+public class TestRandom {
+ @Test
+ public void testRng() {
+ var numbers = new int[5000];
+ var rng = new Rng(4656);
+
+ for (var i = 0; i < 1000000; i++) {
+ var sample = rng.random();
+ var index = (int) (sample * numbers.length);
+ numbers[index] += 1;
+ }
+
+ var avg = (double) Arrays.stream(numbers).sum() / numbers.length;
+ var variance = Arrays.stream(numbers).mapToDouble(num -> Math.pow(num - avg, 2)).sum() / numbers.length;
+ var stdDev = Math.sqrt(variance);
+ var expected = Math.sqrt((double) numbers.length / 12);
+ expected *= 1.1; // adding a bit of margin
+
+ assertTrue("Standard Dev must be less than [" + expected + "] -> [" + stdDev + "]", stdDev < expected);
+ }
+}