View Javadoc
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 }