1 package net.bmahe.genetics4j.neat;
2
3 import org.apache.commons.lang3.Validate;
4 import org.immutables.value.Value;
5
6 /**
7 * Represents a neural network connection in the NEAT (NeuroEvolution of Augmenting Topologies) algorithm.
8 *
9 * <p>A Connection is a fundamental building block of NEAT neural networks, representing a weighted link between two
10 * nodes. Each connection carries essential information for network topology, genetic operations, and evolutionary
11 * tracking through innovation numbers. Connections can be enabled or disabled, allowing for dynamic network topology
12 * exploration during evolution.
13 *
14 * <p>Key properties:
15 * <ul>
16 * <li><strong>Source and target nodes</strong>: Define the directed connection in the network graph</li>
17 * <li><strong>Connection weight</strong>: Determines the strength and polarity of signal transmission</li>
18 * <li><strong>Enabled state</strong>: Controls whether the connection participates in network computation</li>
19 * <li><strong>Innovation number</strong>: Unique identifier for genetic alignment and historical tracking</li>
20 * </ul>
21 *
22 * <p>NEAT algorithm integration:
23 * <ul>
24 * <li><strong>Genetic crossover</strong>: Innovation numbers enable proper gene alignment between parents</li>
25 * <li><strong>Structural mutations</strong>: Connections can be added, removed, or have their state toggled</li>
26 * <li><strong>Weight evolution</strong>: Connection weights are subject to mutation and optimization</li>
27 * <li><strong>Topology innovation</strong>: New connections track the historical order of structural changes</li>
28 * </ul>
29 *
30 * <p>Network computation role:
31 * <ul>
32 * <li><strong>Signal propagation</strong>: Enabled connections transmit weighted signals between nodes</li>
33 * <li><strong>Network evaluation</strong>: Only enabled connections participate in forward propagation</li>
34 * <li><strong>Topology dynamics</strong>: Enable/disable states allow topology exploration without gene loss</li>
35 * <li><strong>Weight optimization</strong>: Connection weights are evolved to optimize network performance</li>
36 * </ul>
37 *
38 * <p>Common usage patterns:
39 *
40 * <pre>{@code
41 * // Create a new connection
42 * Connection connection = Connection.of(0, // from node index
43 * 3, // to node index
44 * 0.75f, // connection weight
45 * true, // enabled state
46 * 42 // innovation number
47 * );
48 *
49 * // Builder pattern for complex construction
50 * Connection connection = Connection.builder()
51 * .fromNodeIndex(1)
52 * .toNodeIndex(4)
53 * .weight(-0.5f)
54 * .isEnabled(false)
55 * .innovation(15)
56 * .build();
57 *
58 * // Copy with modifications
59 * Connection modifiedConnection = Connection.builder()
60 * .from(connection)
61 * .weight(connection.weight() + 0.1f)
62 * .build();
63 * }</pre>
64 *
65 * <p>Innovation number significance:
66 * <ul>
67 * <li><strong>Historical marking</strong>: Tracks when each connection type first appeared in evolution</li>
68 * <li><strong>Genetic alignment</strong>: Enables meaningful crossover between different network topologies</li>
69 * <li><strong>Compatibility distance</strong>: Used to measure genetic similarity for speciation</li>
70 * <li><strong>Structural tracking</strong>: Maintains evolutionary history of network topology changes</li>
71 * </ul>
72 *
73 * <p>Connection state management:
74 * <ul>
75 * <li><strong>Enabled connections</strong>: Actively participate in network computation</li>
76 * <li><strong>Disabled connections</strong>: Preserved in genome but don't affect network output</li>
77 * <li><strong>State mutations</strong>: Can toggle between enabled/disabled states during evolution</li>
78 * <li><strong>Structural preservation</strong>: Disabled connections maintain genetic information</li>
79 * </ul>
80 *
81 * <p>Validation and constraints:
82 * <ul>
83 * <li><strong>Node indices</strong>: Must be non-negative and reference valid nodes in the network</li>
84 * <li><strong>Innovation numbers</strong>: Must be non-negative and unique within the population context</li>
85 * <li><strong>Self-connections</strong>: Typically not allowed (from and to nodes must be different)</li>
86 * <li><strong>Weight bounds</strong>: While not enforced, weights typically range within reasonable bounds</li>
87 * </ul>
88 *
89 * @see NeatChromosome
90 * @see InnovationManager
91 * @see FeedForwardNetwork
92 * @see net.bmahe.genetics4j.neat.mutation.AddConnectionPolicyHandler
93 */
94 @Value.Immutable
95 public interface Connection {
96
97 /**
98 * Returns the index of the source node for this connection.
99 *
100 * @return the source node index (non-negative)
101 */
102 @Value.Parameter
103 int fromNodeIndex();
104
105 /**
106 * Returns the index of the target node for this connection.
107 *
108 * @return the target node index (non-negative)
109 */
110 @Value.Parameter
111 int toNodeIndex();
112
113 /**
114 * Returns the weight of this connection.
115 *
116 * <p>The weight determines the strength and polarity of signal transmission through this connection. Positive
117 * weights amplify signals, negative weights invert them, and zero weights effectively disable signal transmission.
118 *
119 * @return the connection weight
120 */
121 @Value.Parameter
122 float weight();
123
124 /**
125 * Returns whether this connection is enabled.
126 *
127 * <p>Enabled connections participate in network computation and signal propagation. Disabled connections are
128 * preserved in the genome but do not affect network output, allowing for topology exploration without gene loss.
129 *
130 * @return true if the connection is enabled, false otherwise
131 */
132 @Value.Parameter
133 boolean isEnabled();
134
135 /**
136 * Returns the innovation number for this connection.
137 *
138 * <p>Innovation numbers are unique identifiers that track the historical order of structural mutations in the NEAT
139 * algorithm. They enable proper gene alignment during crossover and are used to calculate compatibility distance for
140 * speciation.
141 *
142 * @return the innovation number (non-negative)
143 */
144 @Value.Parameter
145 int innovation();
146
147 @Value.Check
148 default void check() {
149 Validate.isTrue(fromNodeIndex() >= 0);
150 Validate.isTrue(toNodeIndex() >= 0);
151 Validate.isTrue(innovation() >= 0);
152 }
153
154 static class Builder extends ImmutableConnection.Builder {
155 }
156
157 static Builder builder() {
158 return new Builder();
159 }
160
161 /**
162 * Creates a new connection with the specified parameters.
163 *
164 * @param from the source node index
165 * @param to the target node index
166 * @param weight the connection weight
167 * @param isEnabled whether the connection is enabled
168 * @param innovation the innovation number
169 * @return a new connection instance
170 * @throws IllegalArgumentException if node indices or innovation number are negative
171 */
172 static Connection of(final int from, final int to, final float weight, final boolean isEnabled,
173 final int innovation) {
174 return ImmutableConnection.of(from, to, weight, isEnabled, innovation);
175 }
176
177 /**
178 * Creates a copy of the specified connection.
179 *
180 * @param original the connection to copy
181 * @return a new connection instance with the same properties as the original
182 */
183 static Connection copyOf(Connection original) {
184 return ImmutableConnection.copyOf(original);
185 }
186 }