EASystemFactory.java
package net.bmahe.genetics4j.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.Collectors;
import org.apache.commons.lang3.Validate;
import net.bmahe.genetics4j.core.combination.ChromosomeCombinator;
import net.bmahe.genetics4j.core.combination.ChromosomeCombinatorResolver;
import net.bmahe.genetics4j.core.evaluation.FitnessEvaluator;
import net.bmahe.genetics4j.core.evaluation.FitnessEvaluatorBulkAsync;
import net.bmahe.genetics4j.core.evaluation.FitnessEvaluatorSync;
import net.bmahe.genetics4j.core.mutation.MutationPolicyHandlerResolver;
import net.bmahe.genetics4j.core.mutation.Mutator;
import net.bmahe.genetics4j.core.replacement.ReplacementStrategyHandler;
import net.bmahe.genetics4j.core.selection.SelectionPolicyHandlerResolver;
import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
import net.bmahe.genetics4j.core.spec.AbstractEAExecutionContext;
import net.bmahe.genetics4j.core.spec.EAConfiguration;
import net.bmahe.genetics4j.core.spec.EAConfigurationBulkAsync;
import net.bmahe.genetics4j.core.spec.EAExecutionContext;
import net.bmahe.genetics4j.core.spec.combination.CombinationPolicy;
import net.bmahe.genetics4j.core.spec.mutation.MutationPolicy;
/**
* Suite of helper methods to create instances of
* {@link net.bmahe.genetics4j.core.EASystem}
*
*/
public class EASystemFactory {
/**
* Prevents instantiation since it's a bunch of static methods
*/
private EASystemFactory() {
}
public static <T extends Comparable<T>> EASystem<T> from(final AbstractEAConfiguration<T> eaConfiguration,
final AbstractEAExecutionContext<T> eaExecutionContext, final ExecutorService executorService,
final FitnessEvaluator<T> fitnessEvaluator) {
Validate.notNull(eaConfiguration);
Validate.notNull(eaExecutionContext);
Validate.notNull(executorService);
Validate.notNull(fitnessEvaluator);
final var selectionPolicyHandlerResolver = new SelectionPolicyHandlerResolver<T>(eaExecutionContext);
final var parentSelectionPolicyHandler = selectionPolicyHandlerResolver
.resolve(eaConfiguration.parentSelectionPolicy());
final var parentSelector = parentSelectionPolicyHandler.resolve(eaExecutionContext,
eaConfiguration,
selectionPolicyHandlerResolver,
eaConfiguration.parentSelectionPolicy());
final var mutationPolicyHandlerResolver = new MutationPolicyHandlerResolver<T>(eaExecutionContext);
final var chromosomeCombinatorResolver = new ChromosomeCombinatorResolver<T>(eaExecutionContext);
final CombinationPolicy combinationPolicy = eaConfiguration.combinationPolicy();
final List<ChromosomeCombinator<T>> chromosomeCombinators = eaConfiguration.chromosomeSpecs()
.stream()
.map((chromosome) -> {
return chromosomeCombinatorResolver.resolve(combinationPolicy, chromosome);
})
.collect(Collectors.toList());
final List<Mutator> mutators = new ArrayList<>();
final List<MutationPolicy> mutationPolicies = eaConfiguration.mutationPolicies();
for (int i = 0; i < mutationPolicies.size(); i++) {
final var mutationPolicy = mutationPolicies.get(i);
final var mutationPolicyHandler = mutationPolicyHandlerResolver.resolve(mutationPolicy);
final var mutator = mutationPolicyHandler
.createMutator(eaExecutionContext, eaConfiguration, mutationPolicyHandlerResolver, mutationPolicy);
mutators.add(mutator);
}
final var replacementStrategyHandlers = eaExecutionContext.replacementStrategyHandlers();
final var replacementStrategy = eaConfiguration.replacementStrategy();
final Optional<ReplacementStrategyHandler<T>> replacementStrategyHandlerOpt = replacementStrategyHandlers.stream()
.filter(replacementStrategyHandler -> replacementStrategyHandler.canHandle(replacementStrategy))
.findFirst();
final ReplacementStrategyHandler<T> replacementStrategyHandler = replacementStrategyHandlerOpt
.orElseThrow(() -> new IllegalStateException(
"Could not find an implementation to handle the replacement strategy " + replacementStrategy));
final var replacementStrategyImplementor = replacementStrategyHandler
.resolve(eaExecutionContext, eaConfiguration, selectionPolicyHandlerResolver, replacementStrategy);
final long populationSize = eaExecutionContext.populationSize();
return new EASystem<>(eaConfiguration,
populationSize,
chromosomeCombinators,
eaConfiguration.offspringGeneratedRatio(),
parentSelector,
mutators,
replacementStrategyImplementor,
eaExecutionContext,
fitnessEvaluator);
}
/**
* Factory method to create a {@link net.bmahe.genetics4j.core.EASystem} with a
* simple fitness computation method
* <p>
* This is the most common and straight forward approach and ideal when
* computing the fitness is fast and straightforward
*
* @param <T>
* @param eaConfigurationSync
* @param eaExecutionContext
* @param executorService
* @return
*/
public static <T extends Comparable<T>> EASystem<T> from(final EAConfiguration<T> eaConfigurationSync,
final EAExecutionContext<T> eaExecutionContext, final ExecutorService executorService) {
final var fitnessEvaluator = new FitnessEvaluatorSync<>(eaExecutionContext, eaConfigurationSync, executorService);
return from(eaConfigurationSync, eaExecutionContext, executorService, fitnessEvaluator);
}
/**
* Factory method to create a {@link net.bmahe.genetics4j.core.EASystem} with a
* simple fitness computation method.
* <p>
* This is the most common and straight forward approach and ideal when
* computing the fitness is fast and straightforward
*
* @param <T>
* @param eaConfigurationSync
* @param eaExecutionContext
* @return
*/
public static <T extends Comparable<T>> EASystem<T> from(final EAConfiguration<T> eaConfigurationSync,
final EAExecutionContext<T> eaExecutionContext) {
final ExecutorService executorService = ForkJoinPool.commonPool();
return from(eaConfigurationSync, eaExecutionContext, executorService);
}
/**
* Factory method to create a {@link net.bmahe.genetics4j.core.EASystem} with an
* asynchronous fitness computation method
* <p>
* This is an ideal approach when computing fitnesses requires external requests
* or could benefit from bulk processing, such as leveraging GPUs
*
* @param <T>
* @param eaConfigurationBulkAsync
* @param eaExecutionContext
* @param executorService
* @return
*/
public static <T extends Comparable<T>> EASystem<T> from(final EAConfigurationBulkAsync<T> eaConfigurationBulkAsync,
final EAExecutionContext<T> eaExecutionContext, final ExecutorService executorService) {
final var fitnessEvaluator = new FitnessEvaluatorBulkAsync<>(eaConfigurationBulkAsync, executorService);
return from(eaConfigurationBulkAsync, eaExecutionContext, executorService, fitnessEvaluator);
}
/**
* Factory method to create a {@link net.bmahe.genetics4j.core.EASystem} with an
* asynchronous fitness computation method
* <p>
* This is an ideal approach when computing fitnesses requires external requests
* or could benefit from bulk processing, such as leveraging GPUs
*
* @param <T>
* @param eaConfigurationBulkAsync
* @param eaExecutionContext
* @return
*/
public static <T extends Comparable<T>> EASystem<T> from(final EAConfigurationBulkAsync<T> eaConfigurationBulkAsync,
final EAExecutionContext<T> eaExecutionContext) {
final ExecutorService executorService = ForkJoinPool.commonPool();
return from(eaConfigurationBulkAsync, eaExecutionContext, executorService);
}
}