1 package net.bmahe.genetics4j.neat; 2 3 import java.util.concurrent.atomic.AtomicInteger; 4 5 /** 6 * Generates unique identifiers for NEAT (NeuroEvolution of Augmenting Topologies) species. 7 * 8 * <p>SpeciesIdGenerator provides thread-safe generation of unique species identifiers used 9 * to distinguish between different species in the NEAT population. Each species receives 10 * a unique ID that remains constant throughout its lifecycle, enabling species tracking 11 * across generations and proper species management. 12 * 13 * <p>Key characteristics: 14 * <ul> 15 * <li><strong>Thread safety</strong>: Concurrent ID generation for parallel species creation</li> 16 * <li><strong>Uniqueness guarantee</strong>: Each generated ID is unique across the generator's lifetime</li> 17 * <li><strong>Sequential ordering</strong>: IDs are generated in sequential order for consistent tracking</li> 18 * <li><strong>Configurable start</strong>: Initial ID value can be customized for different scenarios</li> 19 * </ul> 20 * 21 * <p>Species lifecycle integration: 22 * <ul> 23 * <li><strong>Species creation</strong>: New species receive unique IDs upon formation</li> 24 * <li><strong>Species tracking</strong>: IDs enable consistent species identification across generations</li> 25 * <li><strong>Population management</strong>: Species IDs facilitate population organization and statistics</li> 26 * <li><strong>Evolution monitoring</strong>: IDs enable tracking of species formation, growth, and extinction</li> 27 * </ul> 28 * 29 * <p>Common usage patterns: 30 * <pre>{@code 31 * // Default species ID generator (starts from 0) 32 * SpeciesIdGenerator generator = new SpeciesIdGenerator(); 33 * 34 * // Custom starting ID 35 * SpeciesIdGenerator customGenerator = new SpeciesIdGenerator(1000); 36 * 37 * // Generate unique species IDs 38 * int speciesId1 = generator.computeNewId(); // Returns 0 39 * int speciesId2 = generator.computeNewId(); // Returns 1 40 * int speciesId3 = generator.computeNewId(); // Returns 2 41 * 42 * // Create species with generated IDs 43 * Species<Double> species1 = new Species<>(speciesId1, ancestors1); 44 * Species<Double> species2 = new Species<>(speciesId2, ancestors2); 45 * 46 * // Thread-safe concurrent generation 47 * CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(generator::computeNewId); 48 * CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(generator::computeNewId); 49 * // Both futures will receive unique IDs 50 * }</pre> 51 * 52 * <p>Integration with NEAT species management: 53 * <ul> 54 * <li><strong>Species formation</strong>: New species created during population organization get unique IDs</li> 55 * <li><strong>Selection handlers</strong>: Used by NeatSelectionPolicyHandler for species tracking</li> 56 * <li><strong>Population statistics</strong>: Enables species-based metrics and analysis</li> 57 * <li><strong>Evolution context</strong>: Integrated into NEAT execution contexts for species management</li> 58 * </ul> 59 * 60 * <p>Thread safety considerations: 61 * <ul> 62 * <li><strong>Atomic operations</strong>: Uses AtomicInteger for thread-safe ID generation</li> 63 * <li><strong>Concurrent access</strong>: Multiple threads can safely generate IDs simultaneously</li> 64 * <li><strong>Lock-free</strong>: No synchronization overhead for high-performance scenarios</li> 65 * <li><strong>Consistency</strong>: Guarantees unique IDs even under high concurrency</li> 66 * </ul> 67 * 68 * <p>Performance characteristics: 69 * <ul> 70 * <li><strong>O(1) generation</strong>: Constant time ID generation</li> 71 * <li><strong>Memory efficient</strong>: Minimal memory footprint with single atomic counter</li> 72 * <li><strong>High throughput</strong>: Suitable for high-frequency species creation</li> 73 * <li><strong>No contention</strong>: Lock-free implementation avoids thread contention</li> 74 * </ul> 75 * 76 * @see Species 77 * @see net.bmahe.genetics4j.neat.selection.NeatSelectionPolicyHandler 78 * @see NeatEAExecutionContexts 79 */ 80 public class SpeciesIdGenerator { 81 82 public static final int DEFAULT_INITIAL_ID = 0; 83 84 private final AtomicInteger currentId; 85 86 /** 87 * Constructs a new species ID generator with the specified initial value. 88 * 89 * <p>The initial value determines the first ID that will be generated. 90 * Subsequent IDs will be incremented sequentially from this starting point. 91 * 92 * @param initialValue the first ID value to generate 93 */ 94 public SpeciesIdGenerator(final int initialValue) { 95 currentId = new AtomicInteger(initialValue); 96 } 97 98 /** 99 * Constructs a new species ID generator with the default initial value (0). 100 */ 101 public SpeciesIdGenerator() { 102 this(DEFAULT_INITIAL_ID); 103 } 104 105 /** 106 * Generates and returns a new unique species ID. 107 * 108 * <p>This method atomically increments the internal counter and returns 109 * the previous value, ensuring that each call produces a unique identifier. 110 * The operation is thread-safe and can be called concurrently from multiple 111 * threads without risk of duplicate IDs. 112 * 113 * @return a unique species identifier 114 */ 115 public int computeNewId() { 116 return currentId.getAndIncrement(); 117 } 118 }