Java tutorial
/* * Copyright (C) 2015 The greyfish authors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.asoem.greyfish.utils.math; import com.google.common.base.Supplier; import com.google.common.primitives.Doubles; import org.apache.commons.math3.distribution.BinomialDistribution; import org.apache.commons.math3.distribution.NormalDistribution; import org.apache.commons.math3.distribution.UniformRealDistribution; import org.apache.commons.math3.random.RandomGenerator; import org.apache.commons.math3.random.SynchronizedRandomGenerator; import org.apache.commons.math3.random.Well19937c; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * A collection of common functions using a {@link RandomGenerator}. */ public final class RandomGenerators { private static final Logger logger = LoggerFactory.getLogger(RandomGenerators.class); /** * Prevent instantiation of this class. */ private RandomGenerators() { throw new AssertionError("Not instantiable"); } /** * @return a singleton instance of the default {@link RandomGenerator}. This method currently delegates to {@link * #well1993c()} */ public static RandomGenerator rng() { return well1993c(); } /** * @return a singleton instance of a {@link Well19937c} random generator. */ public static RandomGenerator well1993c() { return Well19937cHolder.INSTANCE; } /** * Generate a {@code boolean} value which is {@code true} with probability {@code p}. * * @param rng the generator to use * @param p the probability for generating a {@code true} value * @return {@code true} with probability {@code p}, {@code false} otherwise */ public static boolean nextBoolean(final RandomGenerator rng, final double p) { checkArgument(p >= 0 && p <= 1, "p out of range [0, 1]: %s", p); return new BinomialDistribution(rng, 1, p).sample() == 1; } /** * Get a random value in the range [{@code minIncl}, {@code maxExcl}). * * @param rng the generator to use * @param minIncl the minimum inclusive value of the range * @param maxExcl the maximum exclusive value of the range * @return a random number in [{@code minIncl}, {@code maxExcl}) */ public static int nextInt(final RandomGenerator rng, final int minIncl, final int maxExcl) { checkNotNull(rng); checkArgument(maxExcl >= minIncl); return minIncl + rng.nextInt(maxExcl - minIncl); } /** * Generates a random value for the normal distribution with the mean equal to {@code mu} and standard deviation * equal to {@code sigma}. * * @param mu the mean of the distribution * @param sigma the standard deviation of the distribution * @return a random value for the given normal distribution * @deprecated Use {@link #nextNormal(org.apache.commons.math3.random.RandomGenerator, double, double)} */ @Deprecated public static double rnorm(final RandomGenerator rng, final double mu, final double sigma) { return nextNormal(rng, mu, sigma); } /** * Generates a random value for the normal distribution with the mean equal to {@code mu} and standard deviation * equal to {@code sigma}. * * @param mu the mean of the distribution * @param sigma the standard deviation of the distribution * @return a random value for the given normal distribution */ public static double nextNormal(final RandomGenerator rng, final double mu, final double sigma) { final NormalDistribution normalDistribution = new NormalDistribution(rng, mu, sigma, NormalDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY); while (true) { final double sample = normalDistribution.sample(); if (!Doubles.isFinite(sample)) { logger.warn("Discarding non finite sample from normal distribution (mu={}, sigma={}): {}", mu, sigma, sample); continue; } return sample; } } /** * Generates a uniformly distributed random value from the interval [lower,upper). * * @param rng the random generator to use * @param lower the lower bound * @param upper the upper bound * @return a uniformly distributed random value from the interval [lower,upper) */ public static double nextDouble(final RandomGenerator rng, final double lower, final double upper) { final UniformRealDistribution distribution = new UniformRealDistribution(rng, lower, upper); return distribution.sample(); } /** * Get an instance of the default random number generator initialized with {@code seed}. Currently delegates to * {@link #well1993c(long)}. * * @param seed the seed for the generator * @return a new instance of the default random number generator. */ public static RandomGenerator rng(final long seed) { return well1993c(seed); } private static RandomGenerator well1993c(final long seed) { return new Well19937c(seed); } /** * Create a thread safe {@code RandomGenerator} wrapping given {@code randomGenerator}. * * @param randomGenerator the generator to wrap * @return a thread safe {@code RandomGenerator} * @see SynchronizedRandomGenerator */ public static RandomGenerator synchronizedGenerator(final RandomGenerator randomGenerator) { if (randomGenerator instanceof SynchronizedRandomGenerator) { return randomGenerator; } else { return new SynchronizedRandomGenerator(randomGenerator); } } private static class Well19937cHolder implements Serializable { private static final Well19937c INSTANCE = new Well19937c(); // preserving singleton-ness gives equals()/hashCode() for free private Object readResolve() { return INSTANCE; } private static final long serialVersionUID = 0; } /** * Create a {@code RandomGenerator} which delegates all methods to a thread local instance of a generator created by * the given {@code generatorSupplier}. * * @param generatorSupplier the factory to create the thread local instances * @return a new generator delegating to a thread local instance * @see ThreadLocal */ public static RandomGenerator threadLocalGenerator(final Supplier<RandomGenerator> generatorSupplier) { checkNotNull(generatorSupplier); return new ThreadLocalRandomGenerator(generatorSupplier); } private static class ThreadLocalRandomGenerator extends ForwardingRandomGenerator implements Serializable { private final transient ThreadLocal<RandomGenerator> localRandom = new ThreadLocal<RandomGenerator>() { @Override protected RandomGenerator initialValue() { return generatorSupplier.get(); } }; private final Supplier<? extends RandomGenerator> generatorSupplier; public ThreadLocalRandomGenerator(final Supplier<? extends RandomGenerator> generatorSupplier) { this.generatorSupplier = generatorSupplier; } @Override protected RandomGenerator delegate() { return localRandom.get(); } private static final long serialVersionUID = 0; } }