ArraySampler.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.rng.sampling;
- import org.apache.commons.rng.UniformRandomProvider;
- /**
- * Utilities for shuffling an array in-place.
- *
- * <p>Shuffles use the <a
- * href="https://en.wikipedia.org/wiki/Fisher-Yates_shuffle#The_modern_algorithm">
- * Fisher-Yates</a> algorithm.
- *
- * @since 1.6
- */
- public final class ArraySampler {
- /** Class contains only static methods. */
- private ArraySampler() {}
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static boolean[] shuffle(UniformRandomProvider rng, boolean[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static byte[] shuffle(UniformRandomProvider rng, byte[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static char[] shuffle(UniformRandomProvider rng, char[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static double[] shuffle(UniformRandomProvider rng, double[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static float[] shuffle(UniformRandomProvider rng, float[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static int[] shuffle(UniformRandomProvider rng, int[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static long[] shuffle(UniformRandomProvider rng, long[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static short[] shuffle(UniformRandomProvider rng, short[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array.
- *
- * @param <T> Type of the items.
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @return a reference to the given array
- */
- public static <T> T[] shuffle(UniformRandomProvider rng, T[] array) {
- for (int i = array.length; i > 1; i--) {
- swap(array, i - 1, rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static boolean[] shuffle(UniformRandomProvider rng, boolean[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static byte[] shuffle(UniformRandomProvider rng, byte[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static char[] shuffle(UniformRandomProvider rng, char[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static double[] shuffle(UniformRandomProvider rng, double[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static float[] shuffle(UniformRandomProvider rng, float[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static int[] shuffle(UniformRandomProvider rng, int[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static long[] shuffle(UniformRandomProvider rng, long[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static short[] shuffle(UniformRandomProvider rng, short[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Shuffles the entries of the given array in the range {@code [from, to)}.
- *
- * @param <T> Type of the items.
- * @param rng Source of randomness.
- * @param array Array whose entries will be shuffled (in-place).
- * @param from Lower-bound (inclusive) of the sub-range.
- * @param to Upper-bound (exclusive) of the sub-range.
- * @return a reference to the given array
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- public static <T> T[] shuffle(UniformRandomProvider rng, T[] array, int from, int to) {
- final int length = to - checkFromToIndex(from, to, array.length);
- for (int i = length; i > 1; i--) {
- swap(array, from + i - 1, from + rng.nextInt(i));
- }
- return array;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(boolean[] array, int i, int j) {
- final boolean tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(byte[] array, int i, int j) {
- final byte tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(char[] array, int i, int j) {
- final char tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(double[] array, int i, int j) {
- final double tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(float[] array, int i, int j) {
- final float tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(int[] array, int i, int j) {
- final int tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(long[] array, int i, int j) {
- final long tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(short[] array, int i, int j) {
- final short tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Swaps the two specified elements in the array.
- *
- * @param array Array.
- * @param i First index.
- * @param j Second index.
- */
- private static void swap(Object[] array, int i, int j) {
- final Object tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- /**
- * Checks if the sub-range from fromIndex (inclusive) to toIndex (exclusive) is
- * within the bounds of range from 0 (inclusive) to length (exclusive).
- *
- * <p>This function provides the functionality of
- * {@code java.utils.Objects.checkFromToIndex} introduced in JDK 9. The <a
- * href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Objects.html#checkFromToIndex(int,int,int)">Objects</a>
- * javadoc has been reproduced for reference.
- *
- * <p>The sub-range is defined to be out of bounds if any of the following
- * inequalities is true:
- * <ul>
- * <li>{@code fromIndex < 0}
- * <li>{@code fromIndex > toIndex}
- * <li>{@code toIndex > length}
- * <li>{@code length < 0}, which is implied from the former inequalities
- * </ul>
- *
- * @param fromIndex Lower-bound (inclusive) of the sub-range.
- * @param toIndex Upper-bound (exclusive) of the sub-range.
- * @param length Upper-bound (exclusive) of the range
- * @return fromIndex if the sub-range is within the bounds of the range
- * @throws IndexOutOfBoundsException if the sub-range is out of bounds
- */
- private static int checkFromToIndex(int fromIndex, int toIndex, int length) {
- // Checks as documented above
- if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) {
- throw new IndexOutOfBoundsException(
- String.format("Range [%d, %d) out of bounds for length %d", fromIndex, toIndex, length));
- }
- return fromIndex;
- }
- }