Skip to content

Commit

Permalink
randomness improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
cicirello committed Jul 25, 2023
1 parent 16cb639 commit 76ec254
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@

package org.cicirello.search.operators.permutations;

import org.cicirello.math.rand.RandomIndexer;
import org.cicirello.math.rand.EnhancedSplittableGenerator;
import org.cicirello.permutations.Permutation;
import org.cicirello.search.internal.RandomnessFactory;
import org.cicirello.search.operators.IterableMutationOperator;
import org.cicirello.search.operators.MutationIterator;
import org.cicirello.search.operators.UndoableMutationOperator;
Expand All @@ -39,33 +40,43 @@
* @author <a href=https://www.cicirello.org/ target=_top>Vincent A. Cicirello</a>, <a
* href=https://www.cicirello.org/ target=_top>https://www.cicirello.org/</a>
*/
public class SwapMutation
public final class SwapMutation
implements UndoableMutationOperator<Permutation>, IterableMutationOperator<Permutation> {

// needed to implement undo
private final int[] indexes;

private final EnhancedSplittableGenerator generator;

/** Constructs an SwapMutation mutation operator. */
public SwapMutation() {
indexes = new int[2];
generator = RandomnessFactory.createEnhancedSplittableGenerator();
}

private SwapMutation(SwapMutation other) {
generator = other.generator.split();
indexes = new int[2];
}

@Override
public final void mutate(Permutation c) {
public void mutate(Permutation c) {
if (c.length() >= 2) {
generateIndexes(c.length(), indexes);
generator.nextIntPair(c.length(), indexes);
c.swap(indexes[0], indexes[1]);
}
}

@Override
public final void undo(Permutation c) {
if (c.length() >= 2) c.swap(indexes[0], indexes[1]);
public void undo(Permutation c) {
if (c.length() >= 2) {
c.swap(indexes[0], indexes[1]);
}
}

@Override
public SwapMutation split() {
return new SwapMutation();
return new SwapMutation(this);
}

/**
Expand All @@ -80,13 +91,4 @@ public SwapMutation split() {
public MutationIterator iterator(Permutation p) {
return new SwapIterator(p);
}

/*
* This package access method allows the window limited version
* implemented as a subclass to change how indexes are generated
* without modifying the mutate method.
*/
void generateIndexes(int n, int[] indexes) {
RandomIndexer.nextIntPair(n, indexes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@

package org.cicirello.search.operators.permutations;

import org.cicirello.math.rand.RandomIndexer;
import org.cicirello.math.rand.EnhancedSplittableGenerator;
import org.cicirello.permutations.Permutation;
import org.cicirello.search.internal.RandomnessFactory;
import org.cicirello.search.operators.IterableMutationOperator;
import org.cicirello.search.operators.MutationIterator;
import org.cicirello.search.operators.UndoableMutationOperator;

/**
* This class implements a window-limited version of the {@link SwapMutation} mutation operator on
Expand All @@ -44,9 +47,14 @@
* @author <a href=https://www.cicirello.org/ target=_top>Vincent A. Cicirello</a>, <a
* href=https://www.cicirello.org/ target=_top>https://www.cicirello.org/</a>
*/
public final class WindowLimitedSwapMutation extends SwapMutation {
public final class WindowLimitedSwapMutation
implements UndoableMutationOperator<Permutation>, IterableMutationOperator<Permutation> {

private final int limit;
private final EnhancedSplittableGenerator generator;

// needed to implement undo
private final int[] indexes;

/**
* Constructs a WindowLimitedSwapMutation mutation operator with a default window limit of
Expand All @@ -63,27 +71,51 @@ public WindowLimitedSwapMutation() {
* @throws IllegalArgumentException if windowLimit &le; 0
*/
public WindowLimitedSwapMutation(int windowLimit) {
super();
if (windowLimit <= 0) throw new IllegalArgumentException("window limit must be positive");
limit = windowLimit;
generator = RandomnessFactory.createEnhancedSplittableGenerator();
indexes = new int[2];
}

private WindowLimitedSwapMutation(WindowLimitedSwapMutation other) {
limit = other.limit;
generator = other.generator.split();
indexes = new int[2];
}

@Override
public void mutate(Permutation c) {
if (c.length() >= 2) {
generateIndexes(c.length(), indexes);
c.swap(indexes[0], indexes[1]);
}
}

@Override
public void undo(Permutation c) {
if (c.length() >= 2) {
c.swap(indexes[0], indexes[1]);
}
}

@Override
public WindowLimitedSwapMutation split() {
return new WindowLimitedSwapMutation(limit);
return new WindowLimitedSwapMutation(this);
}

@Override
public MutationIterator iterator(Permutation p) {
return new WindowLimitedSwapIterator(p, limit);
}

@Override
final void generateIndexes(int n, int[] indexes) {
/*
* package access to support unit testing
*/
void generateIndexes(int n, int[] indexes) {
if (limit >= n) {
super.generateIndexes(n, indexes);
generator.nextIntPair(n, indexes);
} else {
RandomIndexer.nextWindowedIntPair(n, limit, indexes);
generator.nextWindowedIntPair(n, limit, indexes);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,7 @@ public void testSwap() {
undoTester(m);
mutateTester(m);
splitTester(m);
// Check distribution of random indexes
for (int n = 2; n <= 6; n++) {
boolean[][] indexPairs = new boolean[n][n];
int numSamples = n * (n - 1) * 40;
int[] indexes = new int[2];
for (int i = 0; i < numSamples; i++) {
m.generateIndexes(n, indexes);
indexPairs[indexes[0]][indexes[1]] = true;
}
checkIndexPairs(indexPairs);
}

// Verify mutations are swaps
for (int n = 2; n <= 6; n++) {
Permutation p = new Permutation(n);
Expand Down

0 comments on commit 76ec254

Please sign in to comment.