1 package net.bmahe.genetics4j.neat.mutation;
2
3 import java.util.Objects;
4 import java.util.random.RandomGenerator;
5
6 import net.bmahe.genetics4j.core.chromosomes.Chromosome;
7 import net.bmahe.genetics4j.core.mutation.GenericMutatorImpl;
8 import net.bmahe.genetics4j.core.mutation.MutationPolicyHandler;
9 import net.bmahe.genetics4j.core.mutation.MutationPolicyHandlerResolver;
10 import net.bmahe.genetics4j.core.mutation.Mutator;
11 import net.bmahe.genetics4j.core.mutation.chromosome.ChromosomeMutationHandler;
12 import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
13 import net.bmahe.genetics4j.core.spec.AbstractEAExecutionContext;
14 import net.bmahe.genetics4j.core.spec.mutation.MutationPolicy;
15 import net.bmahe.genetics4j.core.util.ChromosomeResolverUtils;
16 import net.bmahe.genetics4j.neat.InnovationManager;
17 import net.bmahe.genetics4j.neat.spec.mutation.AddConnection;
18
19 /**
20 * Mutation policy handler for NEAT (NeuroEvolution of Augmenting Topologies) add-connection mutations.
21 *
22 * <p>AddConnectionPolicyHandler manages the structural mutation that adds new connections between existing nodes in
23 * NEAT neural networks. This is one of the fundamental structural mutations that enables NEAT to explore different
24 * network topologies by increasing connectivity complexity.
25 *
26 * <p>Add-connection mutation process:
27 * <ol>
28 * <li><strong>Node selection</strong>: Choose source and target nodes for the new connection</li>
29 * <li><strong>Validity checking</strong>: Ensure connection doesn't already exist and doesn't create cycles</li>
30 * <li><strong>Innovation assignment</strong>: Assign unique innovation number to the new connection</li>
31 * <li><strong>Weight initialization</strong>: Set initial weight for the new connection</li>
32 * <li><strong>Connection creation</strong>: Add enabled connection to the chromosome</li>
33 * </ol>
34 *
35 * <p>Key characteristics:
36 * <ul>
37 * <li><strong>Structural evolution</strong>: Increases network connectivity without adding nodes</li>
38 * <li><strong>Innovation tracking</strong>: New connections receive unique innovation numbers</li>
39 * <li><strong>Topology exploration</strong>: Enables discovery of useful connection patterns</li>
40 * <li><strong>Gradual complexity</strong>: Incrementally increases network complexity</li>
41 * </ul>
42 *
43 * <p>Integration with NEAT algorithm:
44 * <ul>
45 * <li><strong>Innovation management</strong>: Coordinates with InnovationManager for tracking</li>
46 * <li><strong>Chromosome mutation</strong>: Delegates to NeatChromosomeAddConnection handler</li>
47 * <li><strong>Population evolution</strong>: Applied based on configured mutation probability</li>
48 * <li><strong>Genetic diversity</strong>: Maintains structural diversity in the population</li>
49 * </ul>
50 *
51 * <p>Common usage patterns:
52 *
53 * <pre>{@code
54 * // Create add-connection mutation policy
55 * AddConnection addConnectionPolicy = AddConnection.of(0.1); // 10% mutation rate
56 *
57 * // Create policy handler
58 * RandomGenerator randomGen = RandomGenerator.getDefault();
59 * AddConnectionPolicyHandler<Double> handler = new AddConnectionPolicyHandler<>(randomGen);
60 *
61 * // Check if handler can process the policy
62 * boolean canHandle = handler.canHandle(resolver, addConnectionPolicy);
63 *
64 * // Create mutator for the policy
65 * Mutator mutator = handler.createMutator(executionContext, configuration, resolver, addConnectionPolicy);
66 *
67 * // Apply mutation to population
68 * List<Individual<Double>> mutatedPopulation = mutator.mutate(configuration, population);
69 * }</pre>
70 *
71 * <p>Mutation policy configuration:
72 * <ul>
73 * <li><strong>Population probability</strong>: Fraction of population to apply mutation to</li>
74 * <li><strong>Individual probability</strong>: Probability of mutating each selected individual</li>
75 * <li><strong>Connection constraints</strong>: Rules governing valid connection additions</li>
76 * <li><strong>Weight initialization</strong>: Strategy for setting initial connection weights</li>
77 * </ul>
78 *
79 * <p>Structural constraints:
80 * <ul>
81 * <li><strong>Duplicate prevention</strong>: Avoids creating connections that already exist</li>
82 * <li><strong>Cycle detection</strong>: Prevents creation of cycles in feed-forward networks</li>
83 * <li><strong>Node validity</strong>: Ensures source and target nodes exist in the network</li>
84 * <li><strong>Self-connection handling</strong>: May prevent or allow self-connections based on policy</li>
85 * </ul>
86 *
87 * <p>Performance considerations:
88 * <ul>
89 * <li><strong>Innovation caching</strong>: Leverages InnovationManager for efficient number assignment</li>
90 * <li><strong>Connection checking</strong>: Efficient algorithms for duplicate and cycle detection</li>
91 * <li><strong>Memory efficiency</strong>: Minimal allocation during mutation operations</li>
92 * <li><strong>Concurrent safety</strong>: Thread-safe for parallel mutation application</li>
93 * </ul>
94 *
95 * @param <T> the fitness value type (typically Double)
96 * @see AddConnection
97 * @see net.bmahe.genetics4j.neat.mutation.chromosome.NeatChromosomeAddConnection
98 * @see MutationPolicyHandler
99 * @see InnovationManager
100 */
101 public class AddConnectionPolicyHandler<T extends Comparable<T>> implements MutationPolicyHandler<T> {
102
103 private final RandomGenerator randomGenerator;
104
105 /**
106 * Constructs a new add-connection policy handler with the specified random generator.
107 *
108 * <p>The random generator is used for stochastic decisions during mutation application, including selection of
109 * individuals to mutate and choices within the mutation process.
110 *
111 * @param _randomGenerator random number generator for stochastic mutation operations
112 * @throws IllegalArgumentException if randomGenerator is null
113 */
114 public AddConnectionPolicyHandler(final RandomGenerator _randomGenerator) {
115 Objects.requireNonNull(_randomGenerator);
116
117 this.randomGenerator = _randomGenerator;
118 }
119
120 /**
121 * Determines whether this handler can process the given mutation policy.
122 *
123 * <p>This handler specifically processes AddConnection mutation policies, which configure the parameters for adding
124 * new connections to NEAT neural networks.
125 *
126 * @param mutationPolicyHandlerResolver resolver for nested mutation policies
127 * @param mutationPolicy the mutation policy to check
128 * @return true if the policy is an AddConnection instance, false otherwise
129 * @throws IllegalArgumentException if any parameter is null
130 */
131 @Override
132 public boolean canHandle(final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver,
133 final MutationPolicy mutationPolicy) {
134 Objects.requireNonNull(mutationPolicyHandlerResolver);
135 Objects.requireNonNull(mutationPolicy);
136
137 return mutationPolicy instanceof AddConnection;
138 }
139
140 /**
141 * Creates a concrete mutator for add-connection mutations.
142 *
143 * <p>This method resolves the appropriate chromosome mutation handlers for NEAT chromosomes and creates a generic
144 * mutator that applies add-connection mutations according to the specified policy parameters.
145 *
146 * <p>Mutator creation process:
147 * <ol>
148 * <li>Extract population mutation probability from the policy</li>
149 * <li>Resolve chromosome-specific mutation handlers</li>
150 * <li>Create generic mutator with resolved components</li>
151 * <li>Return configured mutator ready for population application</li>
152 * </ol>
153 *
154 * @param eaExecutionContext execution context containing NEAT-specific components
155 * @param eaConfiguration evolutionary algorithm configuration
156 * @param mutationPolicyHandlerResolver resolver for chromosome mutation handlers
157 * @param mutationPolicy the add-connection mutation policy
158 * @return a configured mutator for applying add-connection mutations
159 * @throws IllegalArgumentException if any parameter is null
160 */
161 @Override
162 public Mutator createMutator(final AbstractEAExecutionContext<T> eaExecutionContext,
163 final AbstractEAConfiguration<T> eaConfiguration,
164 final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver, MutationPolicy mutationPolicy) {
165 Objects.requireNonNull(eaExecutionContext);
166 Objects.requireNonNull(eaConfiguration);
167 Objects.requireNonNull(mutationPolicy);
168 Objects.requireNonNull(mutationPolicyHandlerResolver);
169
170 final AddConnection addConnectionMutationPolicy = (AddConnection) mutationPolicy;
171 final double populationMutationProbability = addConnectionMutationPolicy.populationMutationProbability();
172
173 final ChromosomeMutationHandler<? extends Chromosome>[] chromosomeMutationHandlers = ChromosomeResolverUtils
174 .resolveChromosomeMutationHandlers(eaExecutionContext, eaConfiguration, mutationPolicy);
175
176 return new GenericMutatorImpl(randomGenerator,
177 chromosomeMutationHandlers,
178 mutationPolicy,
179 populationMutationProbability);
180 }
181 }