umontreal.iro.lecuyer.rng.RandomPermutation Maven / Gradle / Ivy
Show all versions of ssj Show documentation
/*
* Class: RandomPermutation
* Description: Provides methods to randomly shuffle arrays or lists
* Environment: Java
* Software: SSJ
* Copyright (C) 2001 Pierre L'Ecuyer and Université de Montréal
* Organization: DIRO, Université de Montréal
* @author
* @since
* SSJ is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License (GPL) as published by the
* Free Software Foundation, either version 3 of the License, or
* any later version.
* SSJ 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.
* A copy of the GNU General Public License is available at
GPL licence site.
*/
package umontreal.iro.lecuyer.rng;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
/**
* Provides methods to randomly shuffle arrays
* or lists using a random stream.
*
*/
public class RandomPermutation {
private static final int SHUFFLE_THRESHOLD = 5;
/**
* Initializes array with the first n
* positive integers in natural order as array[i - 1] = i, for
* i = 1,..., n. The size of array must be at least n.
*
* @param array the array to initialize.
*
* @param n number of elements initialized.
*
*
*/
public static void init (byte[] array, int n) {
for (byte k = 1; k <= n; k++)
array[k-1] = k;
}
/**
* Similar to {@link #init init}(byte[], int).
*
* @param array the array to initialize.
*
* @param n number of elements initialized.
*
*
*/
public static void init (short[] array, int n) {
for (short k = 1; k <= n; k++)
array[k-1] = k;
}
/**
* Similar to {@link #init init}(byte[], int).
*
* @param array the array to initialize.
*
* @param n number of elements initialized.
*
*
*/
public static void init (int[] array, int n) {
for (int k = 1; k <= n; k++)
array[k-1] = k;
}
/**
* Similar to {@link #init init}(byte[], int).
*
* @param array the array to initialize.
*
* @param n number of elements initialized.
*
*
*/
public static void init (long[] array, int n) {
for (int k = 1; k <= n; k++)
array[k-1] = k;
}
/**
* Similar to {@link #init init}(byte[], int).
*
* @param array the array to initialize.
*
* @param n number of elements initialized.
*
*
*/
public static void init (float[] array, int n) {
for (int k = 1; k <= n; k++)
array[k-1] = k;
}
/**
* Similar to {@link #init init}(byte[], int).
*
*
*
*
* @param array the array to initialize.
*
* @param n number of elements initialized.
*
*
*/
public static void init (double[] array, int n) {
for (int k = 1; k <= n; k++)
array[k-1] = k;
}
@SuppressWarnings("unchecked")
/**
* Same as java.util.Collections.shuffle(List<?>, Random),
* but uses a {@link RandomStream} instead of java.util.Random.
*
* @param list the list being shuffled.
*
* @param stream the random stream used to generate integers.
*
*
*/
public static void shuffle (List> list, RandomStream stream) {
// The implementation is inspired from Sun's Collections.shuffle
final int size = list.size ();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i = size; i > 1; i--)
Collections.swap (list, i - 1, stream.nextInt (0, i - 1));
} else {
final Object arr[] = list.toArray ();
// Shuffle array<
shuffle (arr, stream);
// Dump array back into list
final ListIterator it = list.listIterator ();
for (Object element : arr) {
it.next ();
it.set (element);
}
}
}
/**
* Randomly permutes array using stream.
* This method permutes the whole array.
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (Object[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final Object tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Randomly permutes array using stream.
* This method permutes the whole array.
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (byte[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final byte tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (short[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final short tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (int[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (long[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final long tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (char[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final char tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (boolean[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final boolean tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (float[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final float tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
/**
* Similar to {@link #shuffle shuffle}(byte[], RandomStream).
*
*
*
*
* @param array the array being shuffled.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (double[] array, RandomStream stream) {
final int size = array.length;
for (int i = size - 1; i > 0; i--) {
final int j = stream.nextInt (0, i);
final double tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
@SuppressWarnings("unchecked")
/**
* Partially permutes list as follows using stream:
* draws the first k new elements of list randomly among the n old
* elements of list, assuming that k <= n = list.size().
* In other words, k elements are selected at random without replacement from
* the n list entries and are placed in the first k positions,
* in random order.
*
* @param list the list being shuffled.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate integers.
*
*
*/
public static void shuffle (List> list, int k, RandomStream stream) {
// @precondition 0 <= k <= n <= size.
// The implementation is inspired from Sun's Collections.shuffle
final int size = list.size ();
if (k < 0 || k > size)
throw new IllegalArgumentException("k must be 0 <= k <= list.size()");
if (0 == k) return;
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, size-1);
Collections.swap (list, i, j);
}
} else {
final Object arr[] = list.toArray ();
// Shuffle array<
shuffle (arr, size, k, stream);
// Dump array back into list
final ListIterator it = list.listIterator ();
for (Object element : arr) {
it.next ();
it.set (element);
}
}
}
/**
* Partially permutes array as follows
* using stream: draws the new k elements, array[0] to
* array[k-1], randomly among the old n elements, array[0]
* to array[n-1], assuming that
* k <= n <= array.length.
* In other words, k elements are selected at random without replacement
* from the first n array elements and are placed in the first
* k positions, in random order.
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (Object[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
// Replace by
// if (k < 0 || k > n) throw new IllegalArgumentException();
// or at least assert 0 <= k && k <= n;
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
Object temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (byte[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
byte temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (short[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
short temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (int[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (long[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
long temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (char[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
char temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (boolean[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
boolean temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (float[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
float temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
/**
* Similar to
* {@link #shuffle shuffle}(Object[], n, k, RandomStream).
*
* @param array the array being shuffled.
*
* @param n selection amongst the first n elements.
*
* @param k number of elements selected.
*
* @param stream the random stream used to generate random numbers.
*
*
*/
public static void shuffle (double[] array, int n, int k,
RandomStream stream) {
// @precondition 0 <= k <= n <= a.length.
if (k < 0 || k > n)
throw new IllegalArgumentException("k must be 0 <= k <= n");
for (int i = 0; i < k; i++) {
// Get random j in {i,...,n-1} and interchange a[i] with a[j].
int j = stream.nextInt (i, n-1);
double temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
}