Skip to content

Commit

Permalink
Added configurable source of randomness (#638)
Browse files Browse the repository at this point in the history
* added RandomnessFactory

* synchronized access for thread safety

* seedable RandomnessFactory

* added configurator

* maintain internal random number generator

* operator specific random number generator

* operator internal random number generator

* operator internal PRNG

* Update KPointCrossover.java

* operator internal PRNG

* operator internal PRNG

* operator internal PRNG

* Update UndoableUniformMutation.java

* Update UniformMutation.java

* ThreadLocal PRNG

* constructors that take a PRNG as param

* Update CHANGELOG.md

* operator private PRNG

* operator internal PRNG

* operator internal PRNG

* Update TwoPointCrossover.java

* Update SinglePointCrossover.java

* Update KPointCrossover.java

* operator internal PRNG

* updates to randomness

* Update QuadraticAssignmentProblem.java

* Update BitVector.java

* PRNG improvements

* PRNG improvements

* internal method name change

* PRNG improvements

* PRNG improvements

* Update LargestCommonSubgraph.java

* Removed web monetization pointer

* randomness improvements

* Update CHANGELOG.md

* randomness improvements

* refactor HybridConstructiveHeuristic

* randomness improvements

* randomness improvements

* fix javadoc error

* randomness improvements

* refactor

* refactor

* improved randomness

* minor edits

* refactor

* refactor for randomness improvements

* randomness improvements

* randomness improvements

* refactor  for randomness improvements

* refactor to improve randomness

* refactor

* Update CHANGELOG.md

* documentation updates

* doc update

* refactor randomness generation

* doc edit

* refactor for randomness improvements

* Update SwapIterator.java

* refactor to improve randomness

* randomness improvements

* randomness improvements

* doc edits

* doc edits

* refactor real mutation ops

* improve randomness

* randomness improvements

* randomness improvements

* refactored uniform mutation for integers

* doc edits

* refactor for randomness improvements

* doc edits

* randomness improvements

* randomness improvements

* Update CHANGELOG.md
  • Loading branch information
cicirello authored Jul 27, 2023
1 parent 22e06c8 commit 4422e4f
Show file tree
Hide file tree
Showing 213 changed files with 4,105 additions and 1,550 deletions.
1 change: 0 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ jobs:
path-to-root: gh-pages
user-defined-block: |
<meta name="referrer" content="strict-origin-when-cross-origin">
<meta name="monetization" content="$ilp.uphold.com/RHNKxp4ZeLNE">
<link rel="icon" href="/images/favicon48.png" sizes="16x16 32x32 48x48" type="image/png">
<link rel="icon" href="/images/favicon96.png" sizes="96x96" type="image/png">
<link rel="icon" href="/images/favicon144.png" sizes="144x144" type="image/png">
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] - 2023-06-12
## [Unreleased] - 2023-07-27

### Added
* Added configurable source of randomness (#638).
* New constructors in BitVector class enabling specifying source of randomness for random BitVectors.

### Changed

Expand Down
6 changes: 5 additions & 1 deletion src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@
// space of Permutations may return Permutation
// objects, defined in this module.
requires transitive org.cicirello.jpt;
requires org.cicirello.rho_mu;

// This needs to be transitive because some methods
// take instances of a class from this dependency as
// a parameter.
requires transitive org.cicirello.rho_mu;

// This needs to be transitive due to how Copyable interface
// is used.
Expand Down
134 changes: 134 additions & 0 deletions src/main/java/org/cicirello/search/Configurator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
* Chips-n-Salsa is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chips-n-Salsa 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.cicirello.search;

import java.util.random.RandomGenerator;
import org.cicirello.search.internal.RandomnessFactory;

/**
* This class provides the ability to configure certain library-wide behavior. No library
* configuration is necessary. And in most cases, the default configuration is preferred. See the
* documentation of the methods of this class for details on what can be configured, and why you may
* wish to do so in very limited use-cases.
*
* @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 Configurator {

/*
* private to prevent instantiation as this is a utility class with all static methods
*/
private Configurator() {}

/**
* Configures the random number generator. The library only supports random number generators that
* are "splittable" (i.e., that implements {@link RandomGenerator.SplittableGenerator} rather than
* the more general {@link RandomGenerator}). This is because the library's multithreaded
* functionality relies on the ability to split it as necessary to provide multiple threads with
* dedicated random number generators (e.g., most of Java's built-in random number generators are
* not thread-safe, and those that are, are not thread efficient). Additionally, each operator and
* any other component that requires random numbers, maintains their own instances. The split is
* used to enable this as well.
*
* <p>It should not be necessary to use this method. The default has been chosen for its speed.
* The specific default is not guaranteed to remain the same from one version of the library to
* the next. Any changes to the default will be based upon the speed and other characteristics of
* those that current availability in the Java API.
*
* <p>If you use this method to configure the choice of random number generator, please be aware
* that it will only affect the random number generator in use by operators and other components
* that are instantiated <b>after</b> the call to configureRandomGenerator. Additionally, any
* operators or other components that are split, such as in multithreaded cases, from operators or
* other components that had been instantiated prior to the call to configureRandomGenerator will
* continue to use the previous random number generator algorithm, even if the split occurred
* after the call to configureRandomGenerator. Thus, if you desire to configure the random number
* generator, it is safest to call configureRandomGenerator before doing anything else with the
* library.
*
* <p>Here are a few usage examples:
*
* <pre><code>
* Configurator.configureRandomGenerator(new SplittableRandom());
* Configurator.configureRandomGenerator(new SplittableRandom(100L));
* Configurator.configureRandomGenerator(RandomGenerator.SplittableGenerator.of("SplittableRandom"));
* Configurator.configureRandomGenerator(RandomGenerator.SplittableGenerator.of("L64X128MixRandom"));
* </code></pre>
*
* <p>You are of course not limited to the random number generators built-in to the Java API. You
* can use your own custom random number generator, as long as it is "splittable" and implements
* the {@link RandomGenerator.SplittableGenerator} interface. Here is an example:
*
* <pre><code>
* Configurator.configureRandomGenerator(new MyCustomSplittableGenerator());
* </code></pre>
*
* <p>Also be aware regardless of whatever random number generator you pass here that the library
* replaces the functionality of many of its methods with more efficient algorithms provided by
* the dependency on the <a href="https://rho-mu.cicirello.org/">&rho;&mu;</a> library.
*
* @param r an instance of a class that implements RandomGenerator.SplittableGenerator. This
* parameter is null-safe, treating null as a no-op.
*/
public static void configureRandomGenerator(RandomGenerator.SplittableGenerator r) {
RandomnessFactory.configure(r);
}

/**
* Configures the random number generator with a specified seed. This seeds the first random
* number generator instantiated after the call as specified, with all subsequent random number
* generators split from that one or from an ancestor. This is because the library's multithreaded
* functionality relies on the ability to split it as necessary to provide multiple threads with
* dedicated random number generators (e.g., most of Java's built-in random number generators are
* not thread-safe, and those that are, are not thread efficient). Additionally, each operator and
* any other component that requires random numbers, maintains their own instances. The split is
* used to enable this as well.
*
* <p>This method specifically utilizes the library's default random number generator algorithm.
* If you wish to set a different random number generator algorithm as well as a seed, then use
* the {@link #configureRandomGenerator(RandomGenerator.SplittableGenerator)} method instead and
* pass a pre-seeded instance of your desired random number generator.
*
* <p>If you use this method to seed the random number generator, please be aware that it will
* only affect the random number generator in use by operators and other components that are
* instantiated <b>after</b> the call to configureRandomGenerator. Additionally, any operators or
* other components that are split, such as in multithreaded cases, from operators or other
* components that had been instantiated prior to the call to configureRandomGenerator will
* continue to use the previous random number generator, even if the split occurred after the call
* to configureRandomGenerator. Thus, if you desire to seed the random number generator, it is
* safest to call configureRandomGenerator before doing anything else with the library.
*
* <p>In principle, seeding the random number generator once at the start should enable recreating
* the exact behavior by replicating the exact same sequence of random numbers. This should be
* true even if you are using the library's multithreaded functionality. However, if your use-case
* manages to somehow involve threads instantiating operators or other components concurrently,
* then the non-deterministic ordering associated with concurrency may prevent a guarantee of
* identical behavior for identical seed values. Under normal use of the library, this should not
* be a concern as you would most likely be fully instantiating all parallel algorithms in the
* main thread before execution of those algorithms begins. But none-the-less, the library makes
* no guarantees of full replication of random number sequences in multithreaded applications.
*
* @param seed the seed for the random number generator
*/
public static void configureRandomGenerator(long seed) {
RandomnessFactory.configure(seed);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand All @@ -20,7 +20,8 @@

package org.cicirello.search.evo;

import java.util.concurrent.ThreadLocalRandom;
import org.cicirello.math.rand.EnhancedSplittableGenerator;
import org.cicirello.search.internal.RandomnessFactory;

/**
* This abstract class serves as a base class for selection operators that select population members
Expand All @@ -32,18 +33,23 @@
*/
abstract class AbstractRouletteWheelSelection extends AbstractWeightedSelection {

private final EnhancedSplittableGenerator generator;

/** Construct a roulette wheel selection operator */
public AbstractRouletteWheelSelection() {}
public AbstractRouletteWheelSelection() {
generator = RandomnessFactory.createEnhancedSplittableGenerator();
}

/* package private for use by subclasses in same package */
AbstractRouletteWheelSelection(AbstractRouletteWheelSelection other) {
generator = other.generator.split();
}

@Override
final void selectAll(double[] normalizedWeights, int[] selected) {
for (int i = 0; i < selected.length; i++) {
selected[i] =
selectOne(
normalizedWeights,
0,
normalizedWeights.length - 1,
ThreadLocalRandom.current().nextDouble());
selectOne(normalizedWeights, 0, normalizedWeights.length - 1, generator.nextDouble());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand Down Expand Up @@ -58,12 +58,16 @@
* randomly in the interval [0.05, 0.15], and constrained to the interval [0.01, 0.2].
*
* <p>This specific form of adaptive control parameters is based on the approach described in the
* following paper:<br>
* Vincent A. Cicirello. <a
* following paper:
*
* <p>Vincent A. Cicirello. <a
* href="https://www.cicirello.org/publications/cicirello2015bict.html">Genetic Algorithm Parameter
* Control: Application to Scheduling with Sequence-Dependent Setups</a>. In <i>Proceedings of the
* 9th International Conference on Bio-inspired Information and Communications Technologies</i>,
* pages 136-143. December 2015.
* pages 136-143. December 2015. <a
* href="https://www.cicirello.org/publications/cicirello-bict-2015.pdf">[PDF]</a> <a
* href="https://www.cicirello.org/publications/cicirello2015bict.bib">[BIB]</a> <a
* href="http://dl.acm.org/citation.cfm?id=2954825">[From the ACM Digital Library]</a>
*
* <p>The crossover, mutation, and selection operators are completely configurable by passing
* instances of classes that implement the {@link CrossoverOperator}, {@link MutationOperator}, and
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/org/cicirello/search/evo/AdaptiveGeneration.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand All @@ -20,7 +20,8 @@

package org.cicirello.search.evo;

import java.util.concurrent.ThreadLocalRandom;
import org.cicirello.math.rand.EnhancedSplittableGenerator;
import org.cicirello.search.internal.RandomnessFactory;
import org.cicirello.search.operators.CrossoverOperator;
import org.cicirello.search.operators.MutationOperator;
import org.cicirello.util.Copyable;
Expand All @@ -45,6 +46,7 @@ final class AdaptiveGeneration<T extends Copyable<T>> implements Generation<T> {

private final MutationOperator<T> mutation;
private final CrossoverOperator<T> crossover;
private final EnhancedSplittableGenerator generator;

AdaptiveGeneration(MutationOperator<T> mutation, CrossoverOperator<T> crossover) {
if (mutation == null) {
Expand All @@ -55,12 +57,14 @@ final class AdaptiveGeneration<T extends Copyable<T>> implements Generation<T> {
}
this.mutation = mutation;
this.crossover = crossover;
generator = RandomnessFactory.createEnhancedSplittableGenerator();
}

AdaptiveGeneration(AdaptiveGeneration<T> other) {
// Must be split
mutation = other.mutation.split();
crossover = other.crossover.split();
generator = other.generator.split();
}

@Override
Expand All @@ -75,18 +79,17 @@ public int apply(Population<T> pop) {
// and can be used as parents.
final int LAMBDA = pop.mutableSize();
int count = 0;
ThreadLocalRandom r = ThreadLocalRandom.current();
for (int second = 1; second < LAMBDA; second += 2) {
int first = second - 1;
if (r.nextDouble() < pop.getParameter(first, 0).get()) {
if (generator.nextDouble() < pop.getParameter(first, 0).get()) {
crossover.cross(pop.get(first), pop.get(second));
pop.updateFitness(first);
pop.updateFitness(second);
count += 2;
}
}
for (int j = 0; j < LAMBDA; j++) {
if (r.nextDouble() < pop.getParameter(j, 1).get()) {
if (generator.nextDouble() < pop.getParameter(j, 1).get()) {
mutation.mutate(pop.get(j));
pop.updateFitness(j);
count++;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Chips-n-Salsa: A library of parallel self-adaptive local search algorithms.
* Copyright (C) 2002-2022 Vincent A. Cicirello
* Copyright (C) 2002-2023 Vincent A. Cicirello
*
* This file is part of Chips-n-Salsa (https://chips-n-salsa.cicirello.org/).
*
Expand Down Expand Up @@ -58,7 +58,10 @@
* href="https://www.cicirello.org/publications/cicirello2015bict.html">Genetic Algorithm Parameter
* Control: Application to Scheduling with Sequence-Dependent Setups</a>. In <i>Proceedings of the
* 9th International Conference on Bio-inspired Information and Communications Technologies</i>,
* pages 136-143. December 2015.
* pages 136-143. December 2015. <a
* href="https://www.cicirello.org/publications/cicirello-bict-2015.pdf">[PDF]</a> <a
* href="https://www.cicirello.org/publications/cicirello2015bict.bib">[BIB]</a> <a
* href="http://dl.acm.org/citation.cfm?id=2954825">[From the ACM Digital Library]</a>
*
* <p>The mutation, and selection operators are completely configurable by passing instances of
* classes that implement the {@link MutationOperator}, and {@link SelectionOperator} classes to one
Expand Down
Loading

0 comments on commit 4422e4f

Please sign in to comment.