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.spec.mutation.NeatConnectionWeight;
17
18 /**
19 * Mutation policy handler for NEAT (NeuroEvolution of Augmenting Topologies) connection weight mutations.
20 *
21 * <p>NeatConnectionWeightPolicyHandler manages weight mutations for NEAT neural network connections, which are
22 * essential for fine-tuning network behavior and optimizing performance. Weight mutations are typically the most
23 * frequent type of mutation in NEAT evolution, applied to existing connections to improve network functionality.
24 *
25 * <p>Weight mutation strategies:
26 * <ul>
27 * <li><strong>Gaussian perturbation</strong>: Add small random values to existing weights</li>
28 * <li><strong>Random replacement</strong>: Replace weights with new random values</li>
29 * <li><strong>Creep mutation</strong>: Small incremental changes to weights</li>
30 * <li><strong>Uniform perturbation</strong>: Add uniform random noise to weights</li>
31 * </ul>
32 *
33 * <p>Key characteristics:
34 * <ul>
35 * <li><strong>Behavioral optimization</strong>: Fine-tunes network behavior without changing topology</li>
36 * <li><strong>High frequency</strong>: Applied more often than structural mutations</li>
37 * <li><strong>Bounded values</strong>: Respects chromosome weight bounds during mutation</li>
38 * <li><strong>Continuous evolution</strong>: Enables continuous improvement of network performance</li>
39 * </ul>
40 *
41 * <p>Integration with NEAT algorithm:
42 * <ul>
43 * <li><strong>Chromosome mutation</strong>: Delegates to NEAT chromosome weight mutation handlers</li>
44 * <li><strong>Population evolution</strong>: Applied based on configured mutation probability</li>
45 * <li><strong>Performance optimization</strong>: Primary mechanism for network performance tuning</li>
46 * <li><strong>Genetic diversity</strong>: Maintains behavioral diversity in the population</li>
47 * </ul>
48 *
49 * <p>Common usage patterns:
50 *
51 * <pre>{@code
52 * // Create weight mutation policy
53 * NeatConnectionWeight weightPolicy = NeatConnectionWeight.builder()
54 * .populationMutationProbability(0.8) // 80% of population
55 * .chromosomeMutationProbability(0.9) // 90% of connections per chromosome
56 * .mutationStandardDeviation(0.1) // Standard deviation for Gaussian perturbation
57 * .build();
58 *
59 * // Create policy handler
60 * RandomGenerator randomGen = RandomGenerator.getDefault();
61 * NeatConnectionWeightPolicyHandler<Double> handler = new NeatConnectionWeightPolicyHandler<>(randomGen);
62 *
63 * // Check if handler can process the policy
64 * boolean canHandle = handler.canHandle(resolver, weightPolicy);
65 *
66 * // Create mutator for the policy
67 * Mutator mutator = handler.createMutator(executionContext, configuration, resolver, weightPolicy);
68 * }</pre>
69 *
70 * <p>Weight mutation effects:
71 * <ul>
72 * <li><strong>Performance tuning</strong>: Optimizes network output for better fitness</li>
73 * <li><strong>Exploration vs exploitation</strong>: Balances exploration of weight space with convergence</li>
74 * <li><strong>Gradient-like behavior</strong>: Can simulate gradient-based optimization</li>
75 * <li><strong>Population diversity</strong>: Maintains diverse behavioral patterns</li>
76 * </ul>
77 *
78 * <p>Mutation policy configuration:
79 * <ul>
80 * <li><strong>Population probability</strong>: Fraction of population to apply mutations to</li>
81 * <li><strong>Chromosome probability</strong>: Fraction of connections to mutate per chromosome</li>
82 * <li><strong>Mutation magnitude</strong>: Size of weight perturbations</li>
83 * <li><strong>Mutation type</strong>: Strategy for weight modification (Gaussian, uniform, etc.)</li>
84 * </ul>
85 *
86 * <p>Performance considerations:
87 * <ul>
88 * <li><strong>High frequency application</strong>: Efficient implementation for frequent use</li>
89 * <li><strong>Memory efficiency</strong>: Minimal allocation during weight modification</li>
90 * <li><strong>Numerical stability</strong>: Maintains weight values within valid ranges</li>
91 * <li><strong>Concurrent safety</strong>: Thread-safe for parallel mutation application</li>
92 * </ul>
93 *
94 * @param <T> the fitness value type (typically Double)
95 * @see NeatConnectionWeight
96 * @see net.bmahe.genetics4j.neat.mutation.chromosome.NeatChromosomeConnectionWeightMutationHandler
97 * @see MutationPolicyHandler
98 */
99 public class NeatConnectionWeightPolicyHandler<T extends Comparable<T>> implements MutationPolicyHandler<T> {
100
101 private final RandomGenerator randomGenerator;
102
103 /**
104 * Constructs a new connection weight policy handler with the specified random generator.
105 *
106 * <p>The random generator is used for stochastic decisions during mutation application, including selection of
107 * individuals to mutate and generation of weight perturbations.
108 *
109 * @param _randomGenerator random number generator for stochastic mutation operations
110 * @throws IllegalArgumentException if randomGenerator is null
111 */
112 public NeatConnectionWeightPolicyHandler(final RandomGenerator _randomGenerator) {
113 Objects.requireNonNull(_randomGenerator);
114
115 this.randomGenerator = _randomGenerator;
116 }
117
118 /**
119 * Determines whether this handler can process the given mutation policy.
120 *
121 * <p>This handler specifically processes NeatConnectionWeight mutation policies, which configure the parameters for
122 * mutating connection weights in NEAT neural networks.
123 *
124 * @param mutationPolicyHandlerResolver resolver for nested mutation policies
125 * @param mutationPolicy the mutation policy to check
126 * @return true if the policy is a NeatConnectionWeight instance, false otherwise
127 * @throws IllegalArgumentException if any parameter is null
128 */
129 @Override
130 public boolean canHandle(final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver,
131 final MutationPolicy mutationPolicy) {
132 Objects.requireNonNull(mutationPolicyHandlerResolver);
133 Objects.requireNonNull(mutationPolicy);
134
135 return mutationPolicy instanceof NeatConnectionWeight;
136 }
137
138 /**
139 * Creates a concrete mutator for connection weight mutations.
140 *
141 * <p>This method resolves the appropriate chromosome mutation handlers for NEAT chromosomes and creates a generic
142 * mutator that applies weight mutations according to the specified policy parameters.
143 *
144 * <p>Mutator creation process:
145 * <ol>
146 * <li>Extract population mutation probability from the policy</li>
147 * <li>Resolve chromosome-specific mutation handlers</li>
148 * <li>Create generic mutator with resolved components</li>
149 * <li>Return configured mutator ready for population application</li>
150 * </ol>
151 *
152 * @param eaExecutionContext execution context containing NEAT-specific components
153 * @param eaConfiguration evolutionary algorithm configuration
154 * @param mutationPolicyHandlerResolver resolver for chromosome mutation handlers
155 * @param mutationPolicy the connection weight mutation policy
156 * @return a configured mutator for applying weight mutations
157 * @throws IllegalArgumentException if any parameter is null
158 */
159 @Override
160 public Mutator createMutator(final AbstractEAExecutionContext<T> eaExecutionContext,
161 final AbstractEAConfiguration<T> eaConfiguration,
162 final MutationPolicyHandlerResolver<T> mutationPolicyHandlerResolver, MutationPolicy mutationPolicy) {
163 Objects.requireNonNull(eaExecutionContext);
164 Objects.requireNonNull(eaConfiguration);
165 Objects.requireNonNull(mutationPolicy);
166 Objects.requireNonNull(mutationPolicyHandlerResolver);
167
168 final NeatConnectionWeight neatConnectionWeightMutationPolicy = (NeatConnectionWeight) mutationPolicy;
169 final double populationMutationProbability = neatConnectionWeightMutationPolicy.populationMutationProbability();
170
171 final ChromosomeMutationHandler<? extends Chromosome>[] chromosomeMutationHandlers = ChromosomeResolverUtils
172 .resolveChromosomeMutationHandlers(eaExecutionContext, eaConfiguration, mutationPolicy);
173
174 return new GenericMutatorImpl(randomGenerator,
175 chromosomeMutationHandlers,
176 mutationPolicy,
177 populationMutationProbability);
178 }
179 }