AddConnectionPolicyHandler.java

package net.bmahe.genetics4j.neat.mutation;

import java.util.random.RandomGenerator;

import org.apache.commons.lang3.Validate;

import net.bmahe.genetics4j.core.chromosomes.Chromosome;
import net.bmahe.genetics4j.core.mutation.GenericMutatorImpl;
import net.bmahe.genetics4j.core.mutation.MutationPolicyHandler;
import net.bmahe.genetics4j.core.mutation.MutationPolicyHandlerResolver;
import net.bmahe.genetics4j.core.mutation.Mutator;
import net.bmahe.genetics4j.core.mutation.chromosome.ChromosomeMutationHandler;
import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
import net.bmahe.genetics4j.core.spec.AbstractEAExecutionContext;
import net.bmahe.genetics4j.core.spec.mutation.MutationPolicy;
import net.bmahe.genetics4j.core.util.ChromosomeResolverUtils;
import net.bmahe.genetics4j.neat.spec.mutation.AddConnection;

/**
 * Mutation policy handler for NEAT (NeuroEvolution of Augmenting Topologies) add-connection mutations.
 * 
 * <p>AddConnectionPolicyHandler manages the structural mutation that adds new connections between
 * existing nodes in NEAT neural networks. This is one of the fundamental structural mutations that
 * enables NEAT to explore different network topologies by increasing connectivity complexity.
 * 
 * <p>Add-connection mutation process:
 * <ol>
 * <li><strong>Node selection</strong>: Choose source and target nodes for the new connection</li>
 * <li><strong>Validity checking</strong>: Ensure connection doesn't already exist and doesn't create cycles</li>
 * <li><strong>Innovation assignment</strong>: Assign unique innovation number to the new connection</li>
 * <li><strong>Weight initialization</strong>: Set initial weight for the new connection</li>
 * <li><strong>Connection creation</strong>: Add enabled connection to the chromosome</li>
 * </ol>
 * 
 * <p>Key characteristics:
 * <ul>
 * <li><strong>Structural evolution</strong>: Increases network connectivity without adding nodes</li>
 * <li><strong>Innovation tracking</strong>: New connections receive unique innovation numbers</li>
 * <li><strong>Topology exploration</strong>: Enables discovery of useful connection patterns</li>
 * <li><strong>Gradual complexity</strong>: Incrementally increases network complexity</li>
 * </ul>
 * 
 * <p>Integration with NEAT algorithm:
 * <ul>
 * <li><strong>Innovation management</strong>: Coordinates with InnovationManager for tracking</li>
 * <li><strong>Chromosome mutation</strong>: Delegates to NeatChromosomeAddConnection handler</li>
 * <li><strong>Population evolution</strong>: Applied based on configured mutation probability</li>
 * <li><strong>Genetic diversity</strong>: Maintains structural diversity in the population</li>
 * </ul>
 * 
 * <p>Common usage patterns:
 * <pre>{@code
 * // Create add-connection mutation policy
 * AddConnection addConnectionPolicy = AddConnection.of(0.1);  // 10% mutation rate
 * 
 * // Create policy handler
 * RandomGenerator randomGen = RandomGenerator.getDefault();
 * AddConnectionPolicyHandler<Double> handler = new AddConnectionPolicyHandler<>(randomGen);
 * 
 * // Check if handler can process the policy
 * boolean canHandle = handler.canHandle(resolver, addConnectionPolicy);
 * 
 * // Create mutator for the policy
 * Mutator mutator = handler.createMutator(
 *     executionContext, configuration, resolver, addConnectionPolicy
 * );
 * 
 * // Apply mutation to population
 * List<Individual<Double>> mutatedPopulation = mutator.mutate(
 *     configuration, population
 * );
 * }</pre>
 * 
 * <p>Mutation policy configuration:
 * <ul>
 * <li><strong>Population probability</strong>: Fraction of population to apply mutation to</li>
 * <li><strong>Individual probability</strong>: Probability of mutating each selected individual</li>
 * <li><strong>Connection constraints</strong>: Rules governing valid connection additions</li>
 * <li><strong>Weight initialization</strong>: Strategy for setting initial connection weights</li>
 * </ul>
 * 
 * <p>Structural constraints:
 * <ul>
 * <li><strong>Duplicate prevention</strong>: Avoids creating connections that already exist</li>
 * <li><strong>Cycle detection</strong>: Prevents creation of cycles in feed-forward networks</li>
 * <li><strong>Node validity</strong>: Ensures source and target nodes exist in the network</li>
 * <li><strong>Self-connection handling</strong>: May prevent or allow self-connections based on policy</li>
 * </ul>
 * 
 * <p>Performance considerations:
 * <ul>
 * <li><strong>Innovation caching</strong>: Leverages InnovationManager for efficient number assignment</li>
 * <li><strong>Connection checking</strong>: Efficient algorithms for duplicate and cycle detection</li>
 * <li><strong>Memory efficiency</strong>: Minimal allocation during mutation operations</li>
 * <li><strong>Concurrent safety</strong>: Thread-safe for parallel mutation application</li>
 * </ul>
 * 
 * @param <T> the fitness value type (typically Double)
 * @see AddConnection
 * @see net.bmahe.genetics4j.neat.mutation.chromosome.NeatChromosomeAddConnection
 * @see MutationPolicyHandler
 * @see InnovationManager
 */
public class AddConnectionPolicyHandler<T extends Comparable<T>> implements MutationPolicyHandler<T> {

	private final RandomGenerator randomGenerator;

	/**
	 * Constructs a new add-connection policy handler with the specified random generator.
	 * 
	 * <p>The random generator is used for stochastic decisions during mutation application,
	 * including selection of individuals to mutate and choices within the mutation process.
	 * 
	 * @param _randomGenerator random number generator for stochastic mutation operations
	 * @throws IllegalArgumentException if randomGenerator is null
	 */
	public AddConnectionPolicyHandler(final RandomGenerator _randomGenerator) {
		Validate.notNull(_randomGenerator);

		this.randomGenerator = _randomGenerator;
	}

	/**
	 * Determines whether this handler can process the given mutation policy.
	 * 
	 * <p>This handler specifically processes AddConnection mutation policies, which configure
	 * the parameters for adding new connections to NEAT neural networks.
	 * 
	 * @param mutationPolicyHandlerResolver resolver for nested mutation policies
	 * @param mutationPolicy the mutation policy to check
	 * @return true if the policy is an AddConnection instance, false otherwise
	 * @throws IllegalArgumentException if any parameter is null
	 */
	@Override
	public boolean canHandle(final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver,
			final MutationPolicy mutationPolicy) {
		Validate.notNull(mutationPolicyHandlerResolver);
		Validate.notNull(mutationPolicy);

		return mutationPolicy instanceof AddConnection;
	}

	/**
	 * Creates a concrete mutator for add-connection mutations.
	 * 
	 * <p>This method resolves the appropriate chromosome mutation handlers for NEAT chromosomes
	 * and creates a generic mutator that applies add-connection mutations according to the
	 * specified policy parameters.
	 * 
	 * <p>Mutator creation process:
	 * <ol>
	 * <li>Extract population mutation probability from the policy</li>
	 * <li>Resolve chromosome-specific mutation handlers</li>
	 * <li>Create generic mutator with resolved components</li>
	 * <li>Return configured mutator ready for population application</li>
	 * </ol>
	 * 
	 * @param eaExecutionContext execution context containing NEAT-specific components
	 * @param eaConfiguration evolutionary algorithm configuration
	 * @param mutationPolicyHandlerResolver resolver for chromosome mutation handlers
	 * @param mutationPolicy the add-connection mutation policy
	 * @return a configured mutator for applying add-connection mutations
	 * @throws IllegalArgumentException if any parameter is null
	 */
	@Override
	public Mutator createMutator(final AbstractEAExecutionContext<T> eaExecutionContext,
			final AbstractEAConfiguration<T> eaConfiguration,
			final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver, MutationPolicy mutationPolicy) {
		Validate.notNull(eaExecutionContext);
		Validate.notNull(eaConfiguration);
		Validate.notNull(mutationPolicy);
		Validate.notNull(mutationPolicyHandlerResolver);

		final AddConnection addConnectionMutationPolicy = (AddConnection) mutationPolicy;
		final double populationMutationProbability = addConnectionMutationPolicy.populationMutationProbability();

		final ChromosomeMutationHandler<? extends Chromosome>[] chromosomeMutationHandlers = ChromosomeResolverUtils
				.resolveChromosomeMutationHandlers(eaExecutionContext, eaConfiguration, mutationPolicy);

		return new GenericMutatorImpl(randomGenerator,
				chromosomeMutationHandlers,
				mutationPolicy,
				populationMutationProbability);
	}
}