This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
The following commit(s) were added to refs/heads/master by this push: new 79fbf9d Added more random distribution types to the Complex performance test. 79fbf9d is described below commit 79fbf9d06bf96bffa841ad3abe7e87acb7e70a71 Author: Alex Herbert <aherb...@apache.org> AuthorDate: Thu Jan 30 00:50:42 2020 +0000 Added more random distribution types to the Complex performance test. This adds commons-rng-sampling to the parent pom for use in data generation. --- commons-numbers-examples/examples-jmh/pom.xml | 10 ++++ .../examples/jmh/complex/ComplexPerformance.java | 59 +++++++++++++++++----- pom.xml | 5 ++ 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/commons-numbers-examples/examples-jmh/pom.xml b/commons-numbers-examples/examples-jmh/pom.xml index e29bc68..6d9ff4c 100644 --- a/commons-numbers-examples/examples-jmh/pom.xml +++ b/commons-numbers-examples/examples-jmh/pom.xml @@ -47,6 +47,16 @@ </dependency> <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-rng-simple</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-rng-sampling</artifactId> + </dependency> + + <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>${jmh.version}</version> diff --git a/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/complex/ComplexPerformance.java b/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/complex/ComplexPerformance.java index b22daf7..0517bf3 100644 --- a/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/complex/ComplexPerformance.java +++ b/commons-numbers-examples/examples-jmh/src/main/java/org/apache/commons/numbers/examples/jmh/complex/ComplexPerformance.java @@ -18,6 +18,9 @@ package org.apache.commons.numbers.examples.jmh.complex; import org.apache.commons.numbers.complex.Complex; +import org.apache.commons.rng.UniformRandomProvider; +import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler; +import org.apache.commons.rng.simple.RandomSource; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -31,7 +34,6 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import java.util.Arrays; -import java.util.SplittableRandom; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Predicate; @@ -58,6 +60,9 @@ public class ComplexPerformance { Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.MAX_VALUE, -Double.MAX_VALUE, Double.MIN_VALUE, -Double.MIN_VALUE, 0.0, -0.0, Double.NaN}; + /** The range to use for uniform random numbers. */ + private static final double RANGE = 3.456789; + /** * Contains the size of numbers. */ @@ -90,7 +95,7 @@ public class ComplexPerformance { /** * The type of the data. */ - @Param({"cis", "random", "edge"}) + @Param({"cis", "vector", "log-uniform", "uniform", "edge"}) private String type; /** @@ -107,7 +112,7 @@ public class ComplexPerformance { */ @Setup public void setup() { - numbers = createNumbers(new SplittableRandom()); + numbers = createNumbers(RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP)); } /** @@ -116,12 +121,22 @@ public class ComplexPerformance { * @param rng Random number generator. * @return the random complex number */ - Complex[] createNumbers(SplittableRandom rng) { + Complex[] createNumbers(UniformRandomProvider rng) { Supplier<Complex> generator; if ("cis".equals(type)) { generator = () -> Complex.ofCis(rng.nextDouble() * 2 * Math.PI); - } else if ("random".equals(type)) { - generator = () -> Complex.ofCartesian(createRandomNumber(rng), createRandomNumber(rng)); + } else if ("vector".equals(type)) { + // An unnormalised random vector is created using a Gaussian sample + // for each dimension. Normalisation would create a cis number. + // This is effectively a polar complex number with random modulus + // in [-pi, pi] and random magnitude in a range defined by a Chi-squared + // distribution with 2 degrees of freedom. + final ZigguratNormalizedGaussianSampler s = ZigguratNormalizedGaussianSampler.of(rng); + generator = () -> Complex.ofCartesian(s.sample(), s.sample()); + } else if ("log-uniform".equals(type)) { + generator = () -> Complex.ofCartesian(createLogUniformNumber(rng), createLogUniformNumber(rng)); + } else if ("uniform".equals(type)) { + generator = () -> Complex.ofCartesian(createUniformNumber(rng), createUniformNumber(rng)); } else if ("edge".equals(type)) { generator = () -> Complex.ofCartesian(createEdgeNumber(rng), createEdgeNumber(rng)); } else { @@ -155,7 +170,7 @@ public class ComplexPerformance { @Setup public void setup() { // Do not call super.setup() so we recycle the RNG and avoid duplicates - final SplittableRandom rng = new SplittableRandom(); + final UniformRandomProvider rng = RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP); numbers = createNumbers(rng); numbers2 = createNumbers(rng); } @@ -185,7 +200,7 @@ public class ComplexPerformance { @Setup public void setup() { // Do not call super.setup() so we recycle the RNG and avoid duplicates - final SplittableRandom rng = new SplittableRandom(); + final UniformRandomProvider rng = RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP); numbers = createNumbers(rng); numbers2 = Arrays.stream(createNumbers(rng)).mapToDouble(Complex::real).toArray(); } @@ -207,12 +222,14 @@ public class ComplexPerformance { /** * Creates a random double number with a random sign and mantissa and a large range for - * the exponent. The numbers will not be uniform over the range. + * the exponent. The numbers will not be uniform over the range. This samples randomly + * using the components of a double. The limiting distribution is the log-uniform distribution. * * @param rng Random number generator. * @return the random number + * @see <a href="https://en.wikipedia.org/wiki/Reciprocal_distribution">Reciprocal (log-uniform) distribution</a> */ - private static double createRandomNumber(SplittableRandom rng) { + private static double createLogUniformNumber(UniformRandomProvider rng) { // Create random doubles using random bits in the sign bit and the mantissa. // Then create an exponent in the range -64 to 64. Thus the sum product // of 4 max or min values will not over or underflow. @@ -224,13 +241,29 @@ public class ComplexPerformance { } /** + * Creates a random double number with a random sign and uniform range. + * + * @param rng Random number generator. + * @return the random number + */ + private static double createUniformNumber(UniformRandomProvider rng) { + // Note: [0, 1) - 1 is [-1, 0). + // Since the 1 is a 50/50 sample the result is the interval [-1, 1) + // using the 2^54 dyadic rationals in the interval. + // The range is not critical. The numbers will have approximately 50% + // with the same exponent, max, matching that of RANGE and the rest smaller + // exponents down to (max - 53) since the uniform deviate is limited to 2^-53. + return (rng.nextDouble() - rng.nextInt(1)) * RANGE; + } + + /** * Creates a random double number that will be an edge case: * {@code +/-inf, +/-max, +/-min, +/-0, nan}. * * @param rng Random number generator. * @return the random number */ - private static double createEdgeNumber(SplittableRandom rng) { + private static double createEdgeNumber(UniformRandomProvider rng) { return EDGE_NUMBERS[rng.nextInt(EDGE_NUMBERS.length)]; } @@ -591,8 +624,8 @@ public class ComplexPerformance { } // Binary operations on a complex and a real number. - // These only benchmark methods on the real component as the - // following are expected to be the same speed as the real-only operations + // These only benchmark methods on the real component as the + // following are expected to be the same speed as the real-only operations // given the equivalent primitive operations: // - multiplyImaginary // - divideImaginary diff --git a/pom.xml b/pom.xml index 7e6f48d..9d13e2e 100644 --- a/pom.xml +++ b/pom.xml @@ -179,6 +179,11 @@ <artifactId>commons-rng-simple</artifactId> <version>${numbers.commons.rng.version}</version> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-rng-sampling</artifactId> + <version>${numbers.commons.rng.version}</version> + </dependency> </dependencies> </dependencyManagement>