11#!/usr/bin/env python3
2+ from __future__ import annotations
3+
24from pyrevolve import parser
35from pyrevolve .evolution import fitness
4- from pyrevolve .evolution .selection import multiple_selection , tournament_selection
6+ from pyrevolve .evolution .selection import multiple_selection_with_duplicates , tournament_selection
57from pyrevolve .evolution .speciation .population_speciated import PopulationSpeciated
68from pyrevolve .evolution .speciation .population_speciated_config import PopulationSpeciatedConfig
79from pyrevolve .evolution .speciation .population_speciated_management import steady_state_speciated_population_management
1113from pyrevolve .genotype .lsystem_neat .mutation import LSystemNeatMutationConf as lMutationConfig
1214from pyrevolve .genotype .plasticoding .mutation .mutation import MutationConfig as plasticMutationConfig
1315from pyrevolve .genotype .lsystem_neat .mutation import standard_mutation as lmutation
14-
1516from pyrevolve .util .supervisor .analyzer_queue import AnalyzerQueue
1617from pyrevolve .util .supervisor .simulator_queue import SimulatorQueue
1718from pyrevolve .custom_logging .logger import logger
1819from pyrevolve .genotype .plasticoding import PlasticodingConfig
1920from pyrevolve .genotype .lsystem_neat .lsystem_neat_genotype import LSystemCPGHyperNEATGenotype , LSystemCPGHyperNEATGenotypeConfig
2021from pyrevolve .genotype .neat_brain_genome .neat_brain_genome import NeatBrainGenomeConfig
22+ from .MorphologyCompatibility import MorphologyCompatibility
23+
24+ from typing import TYPE_CHECKING
25+ if TYPE_CHECKING :
26+ from pyrevolve .evolution .individual import Individual
2127
2228
2329async def run ():
@@ -31,7 +37,7 @@ async def run():
3137 offspring_size = 50
3238
3339 body_conf = PlasticodingConfig (
34- max_structural_modules = 20 , # TODO increase
40+ max_structural_modules = 20 ,
3541 allow_vertical_brick = False ,
3642 use_movement_commands = True ,
3743 use_rotation_commands = False ,
@@ -67,17 +73,32 @@ async def run():
6773 crossover_conf = lCrossoverConfig (
6874 crossover_prob = 0.8 ,
6975 )
76+
77+ compatibitity_tester = MorphologyCompatibility (
78+ total_threshold = 1.0 ,
79+ size = 1.0 ,
80+ brick_count = 1.0 ,
81+ proportion = 1.0 ,
82+ coverage = 1.0 ,
83+ joints = 1.5 ,
84+ branching = 1.0 ,
85+ symmetry = 0.0 ,
86+ max_permitted_modules = body_conf .max_structural_modules ,
87+ )
88+
7089 # experiment params #
7190
7291 # Parse command line / file input arguments
7392 args = parser .parse_args ()
7493 experiment_management = ExperimentManagement (args )
94+ has_offspring = False
7595 do_recovery = args .recovery_enabled and not experiment_management .experiment_is_new ()
7696
7797 logger .info (f'Activated run { args .run } of experiment { args .experiment_name } ' )
7898
7999 if do_recovery :
80- gen_num , has_offspring , next_robot_id , next_species_id = experiment_management .read_recovery_state (population_size , offspring_size )
100+ gen_num , has_offspring , next_robot_id , next_species_id = \
101+ experiment_management .read_recovery_state (population_size , offspring_size , species = True )
81102
82103 if gen_num == num_generations - 1 :
83104 logger .info ('Experiment is already complete.' )
@@ -97,9 +118,15 @@ async def run():
97118 if next_species_id < 0 :
98119 next_species_id = 1
99120
100- def are_genomes_compatible_fn (genotype1 : LSystemCPGHyperNEATGenotype ,
101- genotype2 : LSystemCPGHyperNEATGenotype ) -> bool :
102- return genotype1 .is_brain_compatible (genotype2 , genotype_conf )
121+ def are_individuals_brains_compatible_fn (individual1 : Individual ,
122+ individual2 : Individual ) -> bool :
123+ assert isinstance (individual1 .genotype , LSystemCPGHyperNEATGenotype )
124+ assert isinstance (individual2 .genotype , LSystemCPGHyperNEATGenotype )
125+ return individual1 .genotype .is_brain_compatible (individual2 .genotype , genotype_conf )
126+
127+ def are_individuals_morphologies_compatible_fn (individual1 : Individual ,
128+ individual2 : Individual ) -> bool :
129+ return compatibitity_tester .compatible_individuals (individual1 , individual2 )
103130
104131 population_conf = PopulationSpeciatedConfig (
105132 population_size = population_size ,
@@ -111,18 +138,19 @@ def are_genomes_compatible_fn(genotype1: LSystemCPGHyperNEATGenotype,
111138 crossover_operator = lcrossover ,
112139 crossover_conf = crossover_conf ,
113140 selection = lambda individuals : tournament_selection (individuals , 2 ),
114- parent_selection = lambda individuals : multiple_selection (individuals , 2 , tournament_selection ),
141+ parent_selection = lambda individuals : multiple_selection_with_duplicates (individuals , 2 , tournament_selection ),
115142 population_management = steady_state_speciated_population_management ,
116143 population_management_selector = tournament_selection ,
117144 evaluation_time = args .evaluation_time ,
118145 offspring_size = offspring_size ,
119146 experiment_name = args .experiment_name ,
120147 experiment_management = experiment_management ,
121148 # species stuff
122- are_genomes_compatible_fn = are_genomes_compatible_fn ,
149+ # are_individuals_compatible_fn=are_individuals_brains_compatible_fn,
150+ are_individuals_compatible_fn = are_individuals_morphologies_compatible_fn ,
123151 young_age_threshold = 5 ,
124152 young_age_fitness_boost = 2.0 ,
125- old_age_threshold = 20 ,
153+ old_age_threshold = 35 ,
126154 old_age_fitness_penalty = 0.5 ,
127155 species_max_stagnation = 30 ,
128156 )
@@ -142,12 +170,16 @@ def are_genomes_compatible_fn(genotype1: LSystemCPGHyperNEATGenotype,
142170 next_species_id )
143171
144172 if do_recovery :
145- raise NotImplementedError ('recovery not implemented' )
146173 # loading a previous state of the experiment
147174 population .load_snapshot (gen_num )
148175 if gen_num >= 0 :
149176 logger .info (f'Recovered snapshot { gen_num } , pop with { len (population .genus )} individuals' )
150177
178+ # TODO partial recovery is not implemented, this is a substitute
179+ has_offspring = False
180+ next_robot_id = 1 + population .config .population_size + gen_num * population .config .offspring_size
181+ population .next_robot_id = next_robot_id
182+
151183 if has_offspring :
152184 raise NotImplementedError ('partial recovery not implemented' )
153185 recovered_individuals = population .load_partially_completed_generation (gen_num , population_size , offspring_size , next_robot_id )
0 commit comments