Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
details below.

### Added
* Support for all Java 17 random number generators in generating random Permutation objects.

### Changed
* Minimum supported Java version is now Java 17 (breaking change).
* Utilized Java 17 RandomGenerator interface to eliminate redundant code.

### Deprecated

Expand Down
136 changes: 10 additions & 126 deletions src/main/java/org/cicirello/permutations/Permutation.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
*/
package org.cicirello.permutations;

import java.util.Random;
import java.util.SplittableRandom;
import java.util.random.RandomGenerator;
import java.util.concurrent.ThreadLocalRandom;
import java.util.Arrays;
import java.io.Serializable;
Expand Down Expand Up @@ -51,7 +50,7 @@ public final class Permutation implements Serializable, Iterable<Permutation>, C

/**
* Initializes a random permutation of n integers. Uses
* java.util.concurrent.ThreadLocalRandom as the source of efficient random number generation.
* {@link ThreadLocalRandom} as the source of efficient random number generation.
* @param n the length of the permutation
*/
public Permutation(int n) {
Expand All @@ -64,17 +63,7 @@ public Permutation(int n) {
* @param n the length of the permutation
* @param r A source of randomness.
*/
public Permutation(int n, SplittableRandom r) {
permutation = new int[n];
scramble(r);
}

/**
* Initializes a random permutation of n integers.
* @param n the length of the permutation
* @param r A source of randomness.
*/
public Permutation(int n, Random r) {
public Permutation(int n, RandomGenerator r) {
permutation = new int[n];
scramble(r);
}
Expand Down Expand Up @@ -337,7 +326,7 @@ public void invert() {

/**
* Randomly shuffles the permutation. Uses
* java.util.concurrent.ThreadLocalRandom as
* {@link ThreadLocalRandom} as
* the source of efficient random number generation.
*/
public void scramble() {
Expand All @@ -348,30 +337,7 @@ public void scramble() {
* Randomly shuffles the permutation.
* @param r a source of randomness.
*/
public void scramble(Random r) {
if (permutation.length > 0) {
// Since we're scrambling entire permutation, just generate a new
// permutation of integers in [0, n).
// Avoid swapping using trick described in Knuth, Vol 2, page 145,
// last complete paragraph.
permutation[0] = 0;
for (int i = 1; i < permutation.length; i++) {
int j = RandomIndexer.nextInt(i+1, r);
if (j == i) {
permutation[i] = i;
} else {
permutation[i] = permutation[j];
permutation[j] = i;
}
}
}
}

/**
* Randomly shuffles the permutation.
* @param r a source of randomness.
*/
public void scramble(SplittableRandom r) {
public void scramble(RandomGenerator r) {
if (permutation.length > 0) {
// Since we're scrambling entire permutation, just generate a new
// permutation of integers in [0, n).
Expand All @@ -392,7 +358,7 @@ public void scramble(SplittableRandom r) {

/**
* Randomly shuffles the permutation. Uses
* java.util.concurrent.ThreadLocalRandom as
* {@link ThreadLocalRandom} as
* the source of efficient random number generation.
*
* @param guaranteeDifferent if true and if permutation length is at least 2, then method
Expand All @@ -409,32 +375,7 @@ public void scramble(boolean guaranteeDifferent) {
* @param guaranteeDifferent if true and if permutation length is at least 2, then method
* guarantees that the result is a different permutation than it was originally.
*/
public void scramble(Random r, boolean guaranteeDifferent) {
if (guaranteeDifferent) {
boolean changed = false;
for (int i = permutation.length - 1; i > 1; i--) {
int j = RandomIndexer.nextInt(i+1, r);
if (i != j) {
swap(i,j);
changed = true;
}
}
if (permutation.length > 1 && (!changed || r.nextBoolean())) {
swap(0,1);
}
} else {
scramble(r);
}
}

/**
* Randomly shuffles the permutation.
*
* @param r a source of randomness.
* @param guaranteeDifferent if true and if permutation length is at least 2, then method
* guarantees that the result is a different permutation than it was originally.
*/
public void scramble(SplittableRandom r, boolean guaranteeDifferent) {
public void scramble(RandomGenerator r, boolean guaranteeDifferent) {
if (guaranteeDifferent) {
boolean changed = false;
for (int i = permutation.length - 1; i > 1; i--) {
Expand All @@ -454,7 +395,7 @@ public void scramble(SplittableRandom r, boolean guaranteeDifferent) {

/**
* Randomly shuffles a segment. Uses
* java.util.concurrent.ThreadLocalRandom as
* {@link ThreadLocalRandom} as
* the source of efficient random number generation.
* @param i endpoint of the segment
* (precondition: 0 &le; i &lt; length())
Expand All @@ -477,7 +418,7 @@ public void scramble(int i, int j) {
* @throws ArrayIndexOutOfBoundsException if either i or j are negative,
* or if either i or j are greater than or equal to length()
*/
public void scramble(int i, int j, Random r) {
public void scramble(int i, int j, RandomGenerator r) {
if (i==j) { return; }
if (i > j) {
int temp = i;
Expand All @@ -497,63 +438,6 @@ public void scramble(int i, int j, Random r) {
}
}

/**
* Randomly shuffles a segment.
* @param i endpoint of the segment
* (precondition: 0 &le; i &lt; length())
* @param j endpoint of the segment
* (precondition: 0 &le; j &lt; length())
* @param r source of randomness
* @throws ArrayIndexOutOfBoundsException if either i or j are negative,
* or if either i or j are greater than or equal to length()
*/
public void scramble(int i, int j, SplittableRandom r) {
if (i==j) { return; }
if (i > j) {
int temp = i;
i = j;
j = temp;
}
boolean changed = false;
for (int k = j; k > i + 1; k--) {
int l = i + RandomIndexer.nextInt(k-i+1, r);
if (l != k) {
swap(l,k);
changed = true;
}
}
if (!changed || r.nextBoolean()) {
swap(i,i+1);
}
}

/**
* Randomly shuffles a non-contiguous set of permutation elements. As long as there
* are at least 2 different indexes passed to this method, it is guaranteed to
* change the Permutation.
* @param indexes An array of indexes into the permutation. This method assumes
* that the indexes are valid indexes into the permutation. That is, it assumes
* that 0 &le; indexes[i] &lt; this.length().
* @param r source of randomness
* @throws ArrayIndexOutOfBoundsException if any of the indexes[i] are negative or
* greater than or equal to this.length().
*/
public void scramble(int[] indexes, SplittableRandom r) {
if (indexes.length > 1) {
boolean changed = false;
for (int j = indexes.length-1; j > 1; j--) {
int i = RandomIndexer.nextInt(j+1, r);
if (i != j) {
swap(indexes[i],indexes[j]);
changed = true;
}
}
if (!changed || r.nextBoolean()) {
swap(indexes[0],indexes[1]);
}
}
}

/**
* Randomly shuffles a non-contiguous set of permutation elements. As long as there
* are at least 2 different indexes passed to this method, it is guaranteed to
Expand All @@ -565,7 +449,7 @@ public void scramble(int[] indexes, SplittableRandom r) {
* @throws ArrayIndexOutOfBoundsException if any of the indexes[i] are negative or
* greater than or equal to this.length().
*/
public void scramble(int[] indexes, Random r) {
public void scramble(int[] indexes, RandomGenerator r) {
if (indexes.length > 1) {
boolean changed = false;
for (int j = indexes.length-1; j > 1; j--) {
Expand Down