/* Copyright 2009-2015 David Hadka * * This file is part of the MOEA Framework. * * The MOEA Framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The MOEA Framework 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>. */ package org.moeaframework.core; import java.util.Collections; import java.util.List; import java.util.Random; import org.apache.commons.math3.random.MersenneTwister; import org.apache.commons.math3.random.RandomAdaptor; /** * Static methods for generating random or pseudo-random numbers. Any source of * randomness implementing the {@link Random} interface can be used as the * random source. * <p> * {@code PRNG} relies on an underlying source of randomness, and inherits * thread safety from the underlying implementation. Unless the underlying * implementation is known to be thread-safe, assume that {@code PRNG} is not * thread-safe. */ public class PRNG { /** * Internal source of randomness. */ private static Random random; /** * Initialize the static variables. */ static { random = new RandomAdaptor(new MersenneTwister()); } /** * Private constructor to prevent instantiation. */ private PRNG() { super(); } /** * While the preferred method for seeding PRNGs is through the * {@code setRandom} method since methods providing more entropy may be * available * to specific implementations, this method is intended to provide a uniform * interface for setting the seed. * * @param seed the new seed */ public static synchronized void setSeed(long seed) { random.setSeed(seed); } /** * Sets the source of randomness to be used. * * @param random the source of randomness to be used */ public static synchronized void setRandom(Random random) { PRNG.random = random; } /** * Returns the source of randomness currently used. * * @return the source of randomness currently used */ public static Random getRandom() { return random; } /** * Returns the next random, uniformly distributed {@code float} value * between 0.0 and 1.0. * * @return the next random, uniformly distributed {@code float} value * between 0.0 and 1.0 */ public static float nextFloat() { return random.nextFloat(); } /** * Returns the next random, uniformly distributed {@code float} value * between {@code min} and {@code max}. * * @return the next random, uniformly distributed {@code float} value * between {@code min} and {@code max} */ public static float nextFloat(float min, float max) { return min + random.nextFloat() * (max - min); } /** * Returns the next random, uniformly distributed {@code double} value * between 0.0 and 1.0. * * @return the next random, uniformly distributed {@code double} value * between 0.0 and 1.0 */ public static double nextDouble() { return random.nextDouble(); } /** * Returns the next random, uniformly distributed {@code double} value * between {@code min} and {@code max}. * * @return the next random, uniformly distributed {@code double} value * between {@code min} and {@code max} */ public static double nextDouble(double min, double max) { return min + random.nextDouble() * (max - min); } /** * Returns the next random, uniformly distributed {@code int} value between * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE} . * * @return the next random, uniformly distributed {@code int} value between * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}. */ public static int nextInt() { return random.nextInt(); } /** * Returns the next random, uniformly distributed {@code int} value between * {@code 0} (inclusive) and {@code n} (exclusive). * * @return the next random, uniformly distributed {@code int} value between * {@code 0} (inclusive) and {@code n} (exclusive). */ public static int nextInt(int n) { return random.nextInt(n); } /** * Returns the next random, uniformly distributed {@code int} value between * {@code min} and {@code max} (both inclusive). * * @return the next random, uniformly distributed {@code int} value between * {@code min} and {@code max} (both inclusive). */ public static int nextInt(int min, int max) { return min + random.nextInt(max - min + 1); } /** * Returns the next random, uniformly distributed {@code boolean} value. * * @return the next random, uniformly distributed {@code boolean} value. */ public static boolean nextBoolean() { return random.nextBoolean(); } /** * Returns the next random, Gaussian distributed {@code double} value with * mean {@code 0.0} and standard deviation {@code 1.0}. * * @return the next random, Gaussian distributed {@code double} value with * mean {@code 0.0} and standard deviation {@code 1.0}. */ public static double nextGaussian() { return random.nextGaussian(); } /** * Returns the next random, Gaussian distributed {@code double} value with * mean {@code mean} and standard deviation {@code stdev}. * * @return the next random, Gaussian distributed {@code double} value with * mean {@code mean} and standard deviation {@code stdev}. */ public static double nextGaussian(double mean, double stdev) { return stdev * random.nextGaussian() + mean; } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param <T> the type of element stored in the array * @param array the array to be shuffled */ public static <T> void shuffle(T[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { T temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(double[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { double temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(float[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { float temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(long[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { long temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(int[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(short[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { short temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(byte[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { byte temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified array using the same algorithm as * {@link Collections#shuffle}. * * @param array the array to be shuffled */ public static void shuffle(boolean[] array) { for (int i = array.length - 1; i >= 1; i--) { int j = nextInt(i + 1); if (i != j) { boolean temp = array[i]; array[i] = array[j]; array[j] = temp; } } } /** * Shuffles the elements of the specified list by invoking the * {@link Collections#shuffle} method with the internal {@link Random} in * this PRNG. * * @param <T> the type of elements stored in the list * @param list the list to be shuffled */ public static <T> void shuffle(List<T> list) { Collections.shuffle(list, random); } /** * Returns a randomly selected item from the specified list. * * @param <T> the type of the elements stored in the list * @param list the list from which the item is randomly selected * @return a randomly selected item from the specified list */ public static <T> T nextItem(List<T> list) { return list.get(PRNG.nextInt(list.size())); } }