1 | package net.bmahe.genetics4j.neat; | |
2 | ||
3 | import java.util.ArrayList; | |
4 | import java.util.Collection; | |
5 | import java.util.List; | |
6 | import java.util.Objects; | |
7 | ||
8 | import org.apache.commons.lang3.Validate; | |
9 | ||
10 | import net.bmahe.genetics4j.core.Individual; | |
11 | ||
12 | /** | |
13 | * Represents a species in the NEAT (NeuroEvolution of Augmenting Topologies) algorithm. | |
14 | * | |
15 | * <p>A Species groups together genetically similar individuals in the population, enabling | |
16 | * fitness sharing and diversity preservation in NEAT evolution. Species are formed based on | |
17 | * genetic compatibility distance, allowing individuals with similar network topologies to | |
18 | * compete within their own niche rather than with the entire population. | |
19 | * | |
20 | * <p>Key characteristics: | |
21 | * <ul> | |
22 | * <li><strong>Genetic similarity</strong>: Members share similar network topologies and connection patterns</li> | |
23 | * <li><strong>Fitness sharing</strong>: Members compete primarily within their species for reproductive opportunities</li> | |
24 | * <li><strong>Diversity preservation</strong>: Protects innovative topologies from being eliminated by established forms</li> | |
25 | * <li><strong>Dynamic membership</strong>: Species composition changes as individuals evolve and compatibility shifts</li> | |
26 | * </ul> | |
27 | * | |
28 | * <p>NEAT speciation process: | |
29 | * <ol> | |
30 | * <li><strong>Compatibility measurement</strong>: Calculate genetic distance between individuals</li> | |
31 | * <li><strong>Species assignment</strong>: Assign individuals to species based on distance thresholds</li> | |
32 | * <li><strong>Representative selection</strong>: Choose species representatives for compatibility testing</li> | |
33 | * <li><strong>Fitness sharing</strong>: Adjust individual fitness based on species membership size</li> | |
34 | * <li><strong>Reproduction allocation</strong>: Allocate offspring based on species average fitness</li> | |
35 | * </ol> | |
36 | * | |
37 | * <p>Species lifecycle management: | |
38 | * <ul> | |
39 | * <li><strong>Formation</strong>: New species created when individuals exceed compatibility threshold</li> | |
40 | * <li><strong>Growth</strong>: Species gain members as similar individuals are assigned</li> | |
41 | * <li><strong>Stagnation</strong>: Species may stagnate if they fail to improve over generations</li> | |
42 | * <li><strong>Extinction</strong>: Species die out when they have no members or persistently poor performance</li> | |
43 | * </ul> | |
44 | * | |
45 | * <p>Common usage patterns: | |
46 | * <pre>{@code | |
47 | * // Create new species with founding ancestors | |
48 | * List<Individual<Double>> founders = List.of(individual1, individual2); | |
49 | * Species<Double> species = new Species<>(42, founders); | |
50 | * | |
51 | * // Add members during population assignment | |
52 | * species.addMember(similarIndividual1); | |
53 | * species.addMember(similarIndividual2); | |
54 | * species.addAllMembers(batchOfSimilarIndividuals); | |
55 | * | |
56 | * // Access species information | |
57 | * int speciesId = species.getId(); | |
58 | * int memberCount = species.getNumMembers(); | |
59 | * List<Individual<Double>> allMembers = species.getMembers(); | |
60 | * | |
61 | * // Species-based fitness sharing | |
62 | * for (Individual<Double> member : species.getMembers()) { | |
63 | * double sharedFitness = member.fitness() / species.getNumMembers(); | |
64 | * // Use shared fitness for selection | |
65 | * } | |
66 | * }</pre> | |
67 | * | |
68 | * <p>Ancestor tracking: | |
69 | * <ul> | |
70 | * <li><strong>Species representatives</strong>: Ancestors serve as compatibility test references</li> | |
71 | * <li><strong>Historical continuity</strong>: Maintains connection to previous generations</li> | |
72 | * <li><strong>Stability</strong>: Prevents species boundaries from shifting too rapidly</li> | |
73 | * <li><strong>Representative selection</strong>: Best performers may become ancestors for next generation</li> | |
74 | * </ul> | |
75 | * | |
76 | * <p>Fitness sharing mechanism: | |
77 | * <ul> | |
78 | * <li><strong>Within-species competition</strong>: Members primarily compete with each other</li> | |
79 | * <li><strong>Diversity protection</strong>: Prevents single topology from dominating population</li> | |
80 | * <li><strong>Innovation preservation</strong>: Allows new topologies time to optimize</li> | |
81 | * <li><strong>Niche exploitation</strong>: Different species can specialize for different aspects of the problem</li> | |
82 | * </ul> | |
83 | * | |
84 | * <p>Integration with NEAT selection: | |
85 | * <ul> | |
86 | * <li><strong>Speciation</strong>: Used by NeatSelectionPolicyHandler for population organization</li> | |
87 | * <li><strong>Compatibility testing</strong>: Ancestors used as reference points for species assignment</li> | |
88 | * <li><strong>Reproduction allocation</strong>: Species size influences offspring distribution</li> | |
89 | * <li><strong>Population dynamics</strong>: Species creation, growth, and extinction drive population diversity</li> | |
90 | * </ul> | |
91 | * | |
92 | * @param <T> the fitness value type (typically Double) | |
93 | * @see NeatSelectionPolicyHandler | |
94 | * @see SpeciesIdGenerator | |
95 | * @see NeatUtils#computeCompatibilityDistance | |
96 | * @see Individual | |
97 | */ | |
98 | public class Species<T extends Comparable<T>> { | |
99 | ||
100 | private final int id; | |
101 |
2
1. <init> : removed call to java/util/ArrayList::<init> → KILLED 2. <init> : Removed assignment to member variable ancestors → KILLED |
private final List<Individual<T>> ancestors = new ArrayList<>(); |
102 |
2
1. <init> : removed call to java/util/ArrayList::<init> → KILLED 2. <init> : Removed assignment to member variable members → KILLED |
private final List<Individual<T>> members = new ArrayList<>(); |
103 | ||
104 | /** | |
105 | * Constructs a new species with the specified ID and founding ancestors. | |
106 | * | |
107 | * <p>The ancestors serve as reference points for compatibility testing and represent | |
108 | * the genetic heritage of the species. New individuals are tested against these | |
109 | * ancestors to determine species membership. | |
110 | * | |
111 | * @param _id unique identifier for this species | |
112 | * @param _ancestors founding individuals that define the species genetic signature | |
113 | * @throws IllegalArgumentException if ancestors is null | |
114 | */ | |
115 | public Species(final int _id, final List<Individual<T>> _ancestors) { | |
116 | Validate.notNull(_ancestors); | |
117 | ||
118 |
1
1. <init> : Removed assignment to member variable id → SURVIVED |
this.id = _id; |
119 |
1
1. <init> : removed call to java/util/List::addAll → SURVIVED |
ancestors.addAll(_ancestors); |
120 | } | |
121 | ||
122 | /** | |
123 | * Adds an individual as an ancestor of this species. | |
124 | * | |
125 | * <p>Ancestors serve as reference points for compatibility testing in subsequent | |
126 | * generations. Typically, the best performers from a species may be promoted | |
127 | * to ancestors to maintain species continuity. | |
128 | * | |
129 | * @param individual the individual to add as an ancestor | |
130 | * @throws IllegalArgumentException if individual is null | |
131 | */ | |
132 | public void addAncestor(final Individual<T> individual) { | |
133 | Validate.notNull(individual); | |
134 | ||
135 |
1
1. addAncestor : removed call to java/util/List::add → NO_COVERAGE |
ancestors.add(individual); |
136 | } | |
137 | ||
138 | /** | |
139 | * Adds an individual as a member of this species. | |
140 | * | |
141 | * <p>Members are the current generation individuals that have been assigned to | |
142 | * this species based on genetic compatibility. They participate in fitness | |
143 | * sharing and species-based selection. | |
144 | * | |
145 | * @param individual the individual to add as a member | |
146 | * @throws IllegalArgumentException if individual is null | |
147 | */ | |
148 | public void addMember(final Individual<T> individual) { | |
149 | Validate.notNull(individual); | |
150 |
1
1. addMember : removed call to java/util/List::add → KILLED |
members.add(individual); |
151 | } | |
152 | ||
153 | /** | |
154 | * Adds multiple individuals as members of this species. | |
155 | * | |
156 | * <p>This is a convenience method for bulk assignment of compatible individuals | |
157 | * to the species. All individuals in the collection will participate in | |
158 | * fitness sharing within this species. | |
159 | * | |
160 | * @param individuals collection of individuals to add as members | |
161 | * @throws IllegalArgumentException if individuals is null | |
162 | */ | |
163 | public void addAllMembers(final Collection<Individual<T>> individuals) { | |
164 | Validate.notNull(individuals); | |
165 | ||
166 |
1
1. addAllMembers : removed call to java/util/List::addAll → KILLED |
members.addAll(individuals); |
167 | } | |
168 | ||
169 | /** | |
170 | * Returns the number of ancestors in this species. | |
171 | * | |
172 | * <p>Ancestors serve as reference points for compatibility testing and represent | |
173 | * the species genetic heritage from previous generations. | |
174 | * | |
175 | * @return the number of ancestors | |
176 | */ | |
177 | public int getNumAncestors() { | |
178 |
2
1. getNumAncestors : removed call to java/util/List::size → NO_COVERAGE 2. getNumAncestors : replaced int return with 0 for net/bmahe/genetics4j/neat/Species::getNumAncestors → NO_COVERAGE |
return ancestors.size(); |
179 | } | |
180 | ||
181 | /** | |
182 | * Returns the number of current members in this species. | |
183 | * | |
184 | * <p>The member count is used for fitness sharing calculations and reproduction | |
185 | * allocation. Larger species will have their members' fitness values adjusted | |
186 | * downward to prevent single species from dominating the population. | |
187 | * | |
188 | * @return the number of current members | |
189 | */ | |
190 | public int getNumMembers() { | |
191 |
2
1. getNumMembers : removed call to java/util/List::size → KILLED 2. getNumMembers : replaced int return with 0 for net/bmahe/genetics4j/neat/Species::getNumMembers → KILLED |
return members.size(); |
192 | } | |
193 | ||
194 | /** | |
195 | * Returns the unique identifier for this species. | |
196 | * | |
197 | * <p>Species IDs are typically assigned by a SpeciesIdGenerator and remain | |
198 | * constant throughout the species lifecycle. | |
199 | * | |
200 | * @return the species unique identifier | |
201 | */ | |
202 | public int getId() { | |
203 |
1
1. getId : replaced int return with 0 for net/bmahe/genetics4j/neat/Species::getId → SURVIVED |
return id; |
204 | } | |
205 | ||
206 | /** | |
207 | * Returns the list of ancestors for this species. | |
208 | * | |
209 | * <p>Ancestors are reference individuals used for compatibility testing | |
210 | * when assigning new individuals to species. The returned list is mutable | |
211 | * and modifications will affect the species behavior. | |
212 | * | |
213 | * @return mutable list of ancestor individuals | |
214 | */ | |
215 | public List<Individual<T>> getAncestors() { | |
216 |
1
1. getAncestors : replaced return value with Collections.emptyList for net/bmahe/genetics4j/neat/Species::getAncestors → SURVIVED |
return ancestors; |
217 | } | |
218 | ||
219 | /** | |
220 | * Returns the list of current members in this species. | |
221 | * | |
222 | * <p>Members are the current generation individuals that participate in | |
223 | * fitness sharing and species-based selection. The returned list is mutable | |
224 | * and modifications will affect species membership. | |
225 | * | |
226 | * @return mutable list of member individuals | |
227 | */ | |
228 | public List<Individual<T>> getMembers() { | |
229 |
1
1. getMembers : replaced return value with Collections.emptyList for net/bmahe/genetics4j/neat/Species::getMembers → KILLED |
return members; |
230 | } | |
231 | ||
232 | @Override | |
233 | public int hashCode() { | |
234 | return Objects.hash(ancestors, id, members); | |
235 | } | |
236 | ||
237 | // Should it be id only? | |
238 | @Override | |
239 | public boolean equals(Object obj) { | |
240 |
2
1. equals : removed conditional - replaced equality check with true → NO_COVERAGE 2. equals : negated conditional → NO_COVERAGE |
if (this == obj) |
241 |
2
1. equals : Substituted 1 with 0 → NO_COVERAGE 2. equals : replaced boolean return with false for net/bmahe/genetics4j/neat/Species::equals → NO_COVERAGE |
return true; |
242 |
3
1. equals : negated conditional → NO_COVERAGE 2. equals : removed conditional - replaced equality check with true → NO_COVERAGE 3. equals : removed conditional - replaced equality check with false → NO_COVERAGE |
if (obj == null) |
243 |
2
1. equals : replaced boolean return with true for net/bmahe/genetics4j/neat/Species::equals → NO_COVERAGE 2. equals : Substituted 0 with 1 → NO_COVERAGE |
return false; |
244 |
5
1. equals : negated conditional → NO_COVERAGE 2. equals : removed call to java/lang/Object::getClass → NO_COVERAGE 3. equals : removed call to java/lang/Object::getClass → NO_COVERAGE 4. equals : removed conditional - replaced equality check with false → NO_COVERAGE 5. equals : removed conditional - replaced equality check with true → NO_COVERAGE |
if (getClass() != obj.getClass()) |
245 |
2
1. equals : Substituted 0 with 1 → NO_COVERAGE 2. equals : replaced boolean return with true for net/bmahe/genetics4j/neat/Species::equals → NO_COVERAGE |
return false; |
246 | Species other = (Species) obj; | |
247 | return Objects.equals(ancestors, other.ancestors) && id == other.id && Objects.equals(members, other.members); | |
248 | } | |
249 | ||
250 | @Override | |
251 | public String toString() { | |
252 |
3
1. toString : removed call to java/lang/String::valueOf → SURVIVED 2. toString : replaced return value with "" for net/bmahe/genetics4j/neat/Species::toString → SURVIVED 3. toString : removed call to java/lang/String::valueOf → SURVIVED |
return "Species [id=" + id + ", ancestors=" + ancestors + ", members=" + members + "]"; |
253 | } | |
254 | } | |
Mutations | ||
101 |
1.1 2.2 |
|
102 |
1.1 2.2 |
|
118 |
1.1 |
|
119 |
1.1 |
|
135 |
1.1 |
|
150 |
1.1 |
|
166 |
1.1 |
|
178 |
1.1 2.2 |
|
191 |
1.1 2.2 |
|
203 |
1.1 |
|
216 |
1.1 |
|
229 |
1.1 |
|
240 |
1.1 2.2 |
|
241 |
1.1 2.2 |
|
242 |
1.1 2.2 3.3 |
|
243 |
1.1 2.2 |
|
244 |
1.1 2.2 3.3 4.4 5.5 |
|
245 |
1.1 2.2 |
|
252 |
1.1 2.2 3.3 |