@@ -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