All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jenetics.util.RandomRegistry Maven / Gradle / Ivy

There is a newer version: 8.1.0
Show newest version
/*
 * Java Genetic Algorithm Library (jenetics-7.1.2).
 * Copyright (c) 2007-2023 Franz Wilhelmstötter
 *
 * Licensed 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.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package io.jenetics.util;

import static java.util.Objects.requireNonNull;

import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;

/**
 * This class holds the {@link RandomGenerator} engine used for the GA. The
 * {@code RandomRegistry} is thread safe and is initialized with the
 * {@link RandomGeneratorFactory#getDefault()} PRNG.
 *
 * 

Setup the PRNG used for the evolution process

* There are several ways on how to set the {@link RandomGenerator} used during * the evolution process. *

* * Using a {@link RandomGeneratorFactory}
* The following example registers the L128X1024MixRandom random * generator. By using a factory, each threads gets its own generator instance, * which ensures thread-safety without the necessity of the created random * generator to be thread-safe. *

{@code
 * // This is the default setup.
 * RandomRegistry.random(RandomGeneratorFactory.getDefault());
 *
 * // Using the "L128X1024MixRandom" random generator for the evolution.
 * RandomRegistry.random(RandomGeneratorFactory.of("L128X1024MixRandom"));
 * }
*
* * Using a {@link RandomGenerator} {@link Supplier}
* If you have a random engine, which is not available as * {@link RandomGeneratorFactory}, it is also possible to register a * {@link Supplier} of the desired random generator. This method has the same * thread-safety property as the method above. *
{@code
 * RandomRegistry.random(() -> new MySpecialRandomGenerator());
 * }
* * Register a random generator supplier is also more flexible. It allows to * use the streaming and splitting capabilities of the random generators * implemented in the Java library. *
{@code
 * final Iterator randoms =
 *     StreamableGenerator.of("L128X1024MixRandom")
 *         .rngs()
 *         .iterator();
 *
 * RandomRegistry.random(randoms::next);
 * }
*
* * Using a {@link RandomGenerator} instance
* It is also possible to set a single random generator instance for the whole * evolution process. When using this setup, the used random generator must be * thread safe. *
{@code
 * RandomRegistry.random(new Random(123456));
 * }
*

* * The following code snippet shows an almost complete example of a typical * random generator setup. *

{@code
 * public class GA {
 *     public static void main(final String[] args) {
 *         // Initialize the registry with the factory of the PRGN.
 *         final var factory = RandomGeneratorFactory.of("L128X1024MixRandom");
 *         RandomRegistry.random(factory);
 *
 *         final Engine engine = ...;
 *         final EvolutionResult result = engine.stream()
 *             .limit(100)
 *             .collect(toBestEvolutionResult());
 *     }
 * }
 * }
* *

Setup of a local PRNG

* * You can temporarily (and locally) change the implementation of the PRNG. E.g. * for initialize the engine stream with the same initial population. * *
{@code
 * public class GA {
 *     public static void main(final String[] args) {
 *         // Create a reproducible list of genotypes.
 *         final var factory = RandomGeneratorFactory.of("L128X1024MixRandom");
 *         final List> genotypes =
 *             with(factory.create(123), r ->
 *                 Genotype.of(DoubleChromosome.of(0, 10)).instances()
 *                     .limit(50)
 *                     .collect(toList())
 *             );
 *
 *         final Engine engine = ...;
 *         final EvolutionResult result = engine
 *              // Initialize the evolution stream with the given genotypes.
 *             .stream(genotypes)
 *             .limit(100)
 *             .collect(toBestEvolutionResult());
 *     }
 * }
 * }
* * @see RandomGenerator * @see RandomGeneratorFactory * * @author Franz Wilhelmstötter * @since 1.0 * @version 7.0 */ public final class RandomRegistry { private RandomRegistry() {} /** * Thread local wrapper for a random generator supplier (factory). * * @param the type of the random generator */ private static final class TLR extends ThreadLocal implements Supplier { private final Supplier _factory; TLR(final Supplier factory) { _factory = requireNonNull(factory); } @Override protected synchronized R initialValue() { return _factory.get(); } } private static final TLR DEFAULT_RANDOM_FACTORY = new TLR<>(RandomGeneratorFactory.of("L64X256MixRandom")::create); private static final Context> CONTEXT = new Context<>(DEFAULT_RANDOM_FACTORY); /** * Return the {@link RandomGenerator} of the current scope. * * @return the {@link RandomGenerator} of the current scope */ public static RandomGenerator random() { return CONTEXT.get().get(); } /** * Set a new {@link RandomGenerator} for the global scope. The given * {@link RandomGenerator} must be thread safe, which is the case for * the Java {@link Random} class. * * @see #random(RandomGeneratorFactory) * * @param random the new {@link RandomGenerator} for the global * scope * @throws NullPointerException if the {@code random} object is {@code null} */ public static void random(final RandomGenerator random) { requireNonNull(random); CONTEXT.set(() -> random); } /** * Set a new {@link RandomGeneratorFactory} for the global scope. * * @param factory the random generator factory * @throws NullPointerException if the {@code factory} object is {@code null}. */ public static void random(final RandomGeneratorFactory factory) { requireNonNull(factory); CONTEXT.set(new TLR<>(factory::create)); } /** * Set a new {@link Supplier} of {@link RandomGenerator} for the * global scope. * * @param supplier the random generator supplier * @throws NullPointerException if the {@code supplier} object is {@code null}. */ public static void random(final Supplier supplier) { requireNonNull(supplier); CONTEXT.set(new TLR<>(supplier)); } /** * Set the random object to its default value. */ public static void reset() { CONTEXT.reset(); } /** * Executes the consumer code using the given {@code random} generator. * *
{@code
	 * final MSeq seq = ...
	 * using(new Random(123), r -> {
	 *     seq.shuffle();
	 * });
	 * }
* * The example above shuffles the given integer {@code seq} using the * given {@code Random(123)} engine. * * @since 3.0 * * @param random the PRNG used within the consumer * @param consumer the consumer which is executed with the scope of * the given {@code random} engine. * @param the type of the random engine * @throws NullPointerException if one of the arguments is {@code null} */ public static void using( final R random, final Consumer consumer ) { CONTEXT.with( () -> random, r -> { consumer.accept(random); return null; } ); } /** * Executes the consumer code using the given {@code random} generator. * *
{@code
	 * final MSeq seq = ...
	 * using(RandomGeneratorFactory.getDefault(), r -> {
	 *     seq.shuffle();
	 * });
	 * }
* * The example above shuffles the given integer {@code seq} using the * given {@link RandomGeneratorFactory#getDefault()} factory. * * @since 7.0 * * @param factory the random generator factory used within the consumer * @param consumer the consumer which is executed within the scope of * the given random generator. * @param the type of the random engine * @throws NullPointerException if one of the arguments is {@code null} */ public static void using( final RandomGeneratorFactory factory, final Consumer consumer ) { CONTEXT.with( new TLR<>(factory::create), r -> { consumer.accept(r.get()); return null; } ); } /** * Executes the consumer code using the given {@code random} generator * supplier. * *
{@code
	 * final MSeq seq = ...
	 * using(() -> new MyRandomGenerator(), r -> {
	 *     seq.shuffle();
	 * });
	 * }
* * @since 7.0 * * @param supplier the random generator supplier used within the consumer * @param consumer the consumer which is executed within the scope of * the given random generator. * @param the type of the random engine * @throws NullPointerException if one of the arguments is {@code null} */ public static void using( final Supplier supplier, final Consumer consumer ) { CONTEXT.with( new TLR<>(supplier), r -> { consumer.accept(r.get()); return null; } ); } /** * Opens a new scope with the given random generator and executes * the given function within it. The following example shows how to create a * reproducible list of genotypes: *
{@code
	 * final List> genotypes =
	 *     with(new LCG64ShiftRandom(123), r ->
	 *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
	 *            .limit(50)
	 *            .collect(toList())
	 *     );
	 * }
* * @since 3.0 * * @param the type of the random engine * @param the function return type * @param random the PRNG used for the opened scope * @param function the function to apply within the random scope * @return the object returned by the given function * @throws NullPointerException if one of the arguments is {@code null} */ public static T with( final R random, final Function function ) { return CONTEXT.with( () -> random, s -> function.apply(random) ); } /** * Opens a new scope with the given random generator factory and * executes the given function within it. *
{@code
	 * final List> genotypes =
	 *     with(RandomGeneratorFactory.getDefault(), random ->
	 *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
	 *            .limit(50)
	 *            .collect(toList())
	 *     );
	 * }
* * @since 3.0 * * @param the type of the random engine * @param the function return type * @param factory the PRNG used for the opened scope * @param function the function to apply within the random scope * @return the object returned by the given function * @throws NullPointerException if one of the arguments is {@code null}. */ public static T with( final RandomGeneratorFactory factory, final Function function ) { return CONTEXT.with( new TLR<>(factory::create), r -> function.apply(r.get()) ); } /** * Opens a new scope with the given random generator supplier and * executes the given function within it. *
{@code
	 * final List> genotypes =
	 *     with(() -> new MyRandomGenerator(), random ->
	 *         Genotype.of(DoubleChromosome.of(0, 10)).instances()
	 *            .limit(50)
	 *            .collect(toList())
	 *     );
	 * }
* * @since 3.0 * * @param the type of the random engine * @param the function return type * @param supplier the PRNG used for the opened scope * @param function the function to apply within the random scope * @return the object returned by the given function * @throws NullPointerException if one of the arguments is {@code null}. */ public static T with( final Supplier supplier, final Function function ) { return CONTEXT.with( new TLR<>(supplier), r -> function.apply(r.get()) ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy