Skip to content

Commit 6678629

Browse files
author
A-lamo
committed
Fix: Fixed crossover for morphologies.
1 parent 4440f3e commit 6678629

File tree

1 file changed

+16
-19
lines changed

1 file changed

+16
-19
lines changed

examples/y_book/2_body_brain_evolution.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -188,23 +188,22 @@ def crossover_ctrl_vectors(self, ctrl1: list[float], ctrl2: list[float]) -> list
188188
mask = RNG.random(size) < 0.5
189189
child = np.where(mask, arr1, arr2)
190190
return child.tolist()
191-
192-
def crossover_morphologies(self, morph1: Genome, morph2: Genome) -> Genome:
193-
"""Simple morphology crossover: randomly select connections from each parent."""
194-
# Create a new genome based on parent 1
195-
child = morph1.copy()
191+
192+
def crossover_morphologies(self, parent1: Individual, parent2: Individual) -> Genome:
193+
"""Crossover two parent individual morphologies using NEAT crossover."""
194+
# Convert dictionaries to Genome objects
195+
morph1 = Genome.from_dict(parent1.genotype['morph'])
196+
morph2 = Genome.from_dict(parent2.genotype['morph'])
196197

197-
# Randomly replace some connections with parent 2's connections
198-
try:
199-
for conn in child.connections:
200-
if RNG.random() < 0.5 and morph2.connections:
201-
# Randomly pick a connection from parent 2
202-
p2_conn = random.choice(morph2.connections)
203-
conn.weight = p2_conn.weight
204-
except:
205-
pass # If crossover fails, just use child as-is
198+
# Set fitness values so NEAT crossover knows which parent is fitter
199+
morph1.fitness = parent1.fitness if parent1.fitness is not None else float('inf')
200+
morph2.fitness = parent2.fitness if parent2.fitness is not None else float('inf')
201+
202+
# Use the proper NEAT crossover
203+
# This handles weights AND structural changes (topology)
204+
child_genome = morph1.crossover(morph2)
206205

207-
return child
206+
return child_genome
208207

209208
# ------------------------------------------------------------------------ #
210209
# EA OPERATORS #
@@ -256,11 +255,9 @@ def reproduction(self, population: Population) -> Population:
256255
if use_sexual:
257256
# Select two parents for crossover
258257
p1, p2 = random.sample(parents, 2)
259-
p1_morph = Genome.from_dict(p1.genotype['morph'])
260-
p2_morph = Genome.from_dict(p2.genotype['morph'])
261258

262-
# Crossover morphologies
263-
c_morph = self.crossover_morphologies(p1_morph, p2_morph)
259+
# Crossover morphologies (method handles Genome conversion)
260+
c_morph = self.crossover_morphologies(p1, p2)
264261

265262
# Crossover brain vectors
266263
c_ctrl = self.crossover_ctrl_vectors(p1.genotype['ctrl'], p2.genotype['ctrl'])

0 commit comments

Comments
 (0)