1 package net.bmahe.genetics4j.neat.spec.combination;
2
3 import org.apache.commons.lang3.Validate;
4 import org.immutables.value.Value;
5
6 import net.bmahe.genetics4j.core.spec.combination.CombinationPolicy;
7 import net.bmahe.genetics4j.neat.spec.combination.parentcompare.ParentComparisonPolicy;
8 import net.bmahe.genetics4j.neat.spec.combination.parentcompare.FitnessComparison;
9
10 /**
11 * Configuration policy for NEAT (NeuroEvolution of Augmenting Topologies) genetic crossover operations.
12 *
13 * <p>NeatCombination defines how neural network chromosomes should be recombined during genetic crossover, including
14 * inheritance biases, gene re-enabling policies, and parent comparison strategies. This policy controls the fundamental
15 * genetic operators that shape network topology evolution in NEAT.
16 *
17 * <p>Key crossover parameters:
18 * <ul>
19 * <li><strong>Inheritance threshold</strong>: Bias toward fitter parent for gene inheritance</li>
20 * <li><strong>Gene re-enabling</strong>: Probability of re-enabling disabled genes during crossover</li>
21 * <li><strong>Parent comparison</strong>: Strategy for determining relative parent fitness</li>
22 * <li><strong>Genetic alignment</strong>: Innovation-number-based gene matching</li>
23 * </ul>
24 *
25 * <p>NEAT genetic crossover process:
26 * <ol>
27 * <li><strong>Gene alignment</strong>: Match genes by innovation number between parents</li>
28 * <li><strong>Matching genes</strong>: Randomly inherit from either parent (biased by inheritance threshold)</li>
29 * <li><strong>Disjoint genes</strong>: Inherit from fitter parent based on parent comparison</li>
30 * <li><strong>Excess genes</strong>: Inherit from fitter parent beyond less fit parent's range</li>
31 * <li><strong>Gene state</strong>: Apply re-enabling policy to disabled genes</li>
32 * </ol>
33 *
34 * <p>Gene inheritance strategies:
35 * <ul>
36 * <li><strong>Matching genes</strong>: Present in both parents with same innovation number</li>
37 * <li><strong>Disjoint genes</strong>: Present in one parent within other parent's innovation range</li>
38 * <li><strong>Excess genes</strong>: Present in one parent beyond other parent's highest innovation</li>
39 * <li><strong>Disabled genes</strong>: May be re-enabled based on re-enabling threshold</li>
40 * </ul>
41 *
42 * <p>Common usage patterns:
43 *
44 * <pre>{@code
45 * // Default NEAT crossover configuration
46 * NeatCombination defaultPolicy = NeatCombination.build();
47 *
48 * // Custom crossover with fitness bias
49 * NeatCombination biasedPolicy = NeatCombination.builder()
50 * .inheritanceThresold(0.7) // 70% bias toward fitter parent
51 * .reenableGeneInheritanceThresold(0.3) // 30% chance to re-enable genes
52 * .parentComparisonPolicy(FitnessComparison.build())
53 * .build();
54 *
55 * // Unbiased crossover for diversity
56 * NeatCombination unbiasedPolicy = NeatCombination.builder()
57 * .inheritanceThresold(0.5) // No bias toward either parent
58 * .reenableGeneInheritanceThresold(0.1) // Low re-enabling rate
59 * .build();
60 *
61 * // Use in EA configuration
62 * var combinationSpec = ChromosomeCombinatorSpec.builder().combinationPolicy(biasedPolicy).build();
63 * }</pre>
64 *
65 * <p>Inheritance threshold effects:
66 * <ul>
67 * <li><strong>0.5 (default)</strong>: Unbiased inheritance, equal probability from both parents</li>
68 * <li><strong>> 0.5</strong>: Bias toward fitter parent, promotes convergence</li>
69 * <li><strong>< 0.5</strong>: Bias toward less fit parent, increases diversity</li>
70 * <li><strong>1.0</strong>: Always inherit from fitter parent (if determinable)</li>
71 * </ul>
72 *
73 * <p>Gene re-enabling mechanism:
74 * <ul>
75 * <li><strong>Historical information</strong>: Disabled genes preserve connection topology</li>
76 * <li><strong>Re-activation chance</strong>: Allows previously disabled connections to contribute again</li>
77 * <li><strong>Topology exploration</strong>: Enables rediscovery of useful connection patterns</li>
78 * <li><strong>Genetic diversity</strong>: Prevents permanent loss of structural information</li>
79 * </ul>
80 *
81 * <p>Parent comparison integration:
82 * <ul>
83 * <li><strong>Fitness comparison</strong>: Standard fitness-based parent ranking</li>
84 * <li><strong>Custom strategies</strong>: Pluggable comparison policies for different problem domains</li>
85 * <li><strong>Multi-objective support</strong>: Compatible with complex fitness landscapes</li>
86 * <li><strong>Equal fitness handling</strong>: Special rules when parents have identical fitness</li>
87 * </ul>
88 *
89 * <p>Performance considerations:
90 * <ul>
91 * <li><strong>Innovation sorting</strong>: Leverages pre-sorted connection lists for O(n) crossover</li>
92 * <li><strong>Memory efficiency</strong>: Minimal allocation during gene inheritance</li>
93 * <li><strong>Cache-friendly</strong>: Sequential access patterns for better cache performance</li>
94 * <li><strong>Parallelizable</strong>: Crossover operations can be executed concurrently</li>
95 * </ul>
96 *
97 * @see ParentComparisonPolicy
98 * @see FitnessComparison
99 * @see net.bmahe.genetics4j.neat.combination.NeatChromosomeCombinator
100 * @see CombinationPolicy
101 */
102 @Value.Immutable
103 public interface NeatCombination extends CombinationPolicy {
104
105 public static final double DEFAULT_INHERITANCE_THRESHOLD = 0.5d;
106
107 public static final double DEFAULT_REENABLE_GENE_INHERITANCE_THRESHOLD = 0.25d;
108
109 /**
110 * Returns the inheritance threshold for biasing gene selection toward fitter parents.
111 *
112 * <p>This threshold controls the probability of inheriting genes from the fitter parent during crossover. Higher
113 * values bias inheritance toward the better performing parent, while lower values provide more equal inheritance or
114 * even bias toward the less fit parent.
115 *
116 * <p>Inheritance behavior:
117 * <ul>
118 * <li><strong>0.5 (default)</strong>: Unbiased inheritance, equal probability from both parents</li>
119 * <li><strong>> 0.5</strong>: Bias toward fitter parent, promotes convergence to good solutions</li>
120 * <li><strong>< 0.5</strong>: Bias toward less fit parent, increases population diversity</li>
121 * <li><strong>1.0</strong>: Always inherit from fitter parent when fitness differs</li>
122 * <li><strong>0.0</strong>: Always inherit from less fit parent when fitness differs</li>
123 * </ul>
124 *
125 * @return inheritance threshold value between 0.0 and 1.0 (inclusive)
126 */
127 @Value.Default
128 default public double inheritanceThresold() {
129 return DEFAULT_INHERITANCE_THRESHOLD;
130 }
131
132 /**
133 * Returns the threshold for re-enabling disabled genes during crossover.
134 *
135 * <p>When a gene (connection) is disabled in one parent but enabled in the other, this threshold determines the
136 * probability that the gene will be enabled in the offspring. This mechanism prevents permanent loss of potentially
137 * useful connections and allows rediscovery of structural innovations.
138 *
139 * <p>Re-enabling behavior:
140 * <ul>
141 * <li><strong>0.25 (default)</strong>: 25% chance to re-enable disabled connections</li>
142 * <li><strong>0.0</strong>: Never re-enable disabled connections</li>
143 * <li><strong>1.0</strong>: Always re-enable connections that are enabled in either parent</li>
144 * <li><strong>Higher values</strong>: More aggressive topology exploration</li>
145 * <li><strong>Lower values</strong>: More conservative structural preservation</li>
146 * </ul>
147 *
148 * @return re-enabling threshold value between 0.0 and 1.0 (inclusive)
149 */
150 @Value.Default
151 default public double reenableGeneInheritanceThresold() {
152 return DEFAULT_REENABLE_GENE_INHERITANCE_THRESHOLD;
153 }
154
155 /**
156 * Returns the policy used to compare parent fitness for inheritance decisions.
157 *
158 * <p>The parent comparison policy determines which parent is considered "fitter" for the purposes of biased gene
159 * inheritance. This affects how disjoint and excess genes are inherited and how the inheritance threshold is
160 * applied.
161 *
162 * <p>Available comparison strategies:
163 * <ul>
164 * <li><strong>FitnessComparison (default)</strong>: Compare parents based on their fitness values</li>
165 * <li><strong>Custom policies</strong>: Pluggable strategies for domain-specific comparisons</li>
166 * <li><strong>Multi-objective</strong>: Specialized comparisons for multi-objective optimization</li>
167 * <li><strong>Equal fitness handling</strong>: Specific behavior when parents have identical fitness</li>
168 * </ul>
169 *
170 * @return the parent comparison policy (defaults to fitness-based comparison)
171 */
172 @Value.Default
173 default public ParentComparisonPolicy parentComparisonPolicy() {
174 return FitnessComparison.build();
175 }
176
177 @Value.Check
178 default void check() {
179 Validate.inclusiveBetween(0, 1, inheritanceThresold());
180 Validate.inclusiveBetween(0, 1, reenableGeneInheritanceThresold());
181 }
182
183 class Builder extends ImmutableNeatCombination.Builder {
184 }
185
186 static Builder builder() {
187 return new Builder();
188 }
189
190 /**
191 * Creates a NEAT combination policy with default settings.
192 *
193 * <p>Default configuration:
194 * <ul>
195 * <li>Inheritance threshold: 0.5 (unbiased)</li>
196 * <li>Gene re-enabling threshold: 0.25 (25% chance)</li>
197 * <li>Parent comparison: Fitness-based comparison</li>
198 * </ul>
199 *
200 * @return a new NEAT combination policy with default settings
201 */
202 static NeatCombination build() {
203 return builder().build();
204 }
205
206 }