Source code for Evolution

 1"""Main evolution loop orchestrator.
 2
 3Wires together the protocol implementations (population generation,
 4circuit factory, fitness evaluation, reproduction) and runs the
 5generational evolution loop with async hardware measurements.
 6
 7.. warning::
 8    This module is marked as NOT CURRENT VERSION. See
 9    :class:`~TrivialImplementation.TrivialEvolution` for the reference
10    implementation currently used for testing.
11"""
12
13from BitstreamEvolutionProtocols import CircuitFactory, EvaluatePopulationFitness, GenDataFactory, GenerateMeasurements, Hardware, Population, Reproducer
14from PlotDataRecorder import PlotDataRecorder
15from Population.PopulationInitialization import GenerateInitialPopulations
16
17import asyncio
18
[docs] 19class Evolution: 20 """ 21 NOT CURRENT VERSION, SHOULD BE REVISED USING TRIVIAL_EVOLUTION 22 This class utilizes the protocols defined to run experiments 23 There is only one implementation of Evolution needed 24 If there are any desired features that are not supported in this version of the class 25 then this class should be modified to support them *and* preserve existing behavior 26 """ 27
[docs] 28 def __init__(self, gen_data_factory: GenDataFactory, circuit_factory: CircuitFactory, reproduce: Reproducer, 29 gen_init_populations: GenerateInitialPopulations, eval_population_fitness: EvaluatePopulationFitness, 30 generate_measurements: GenerateMeasurements, hardware: Hardware, plot_data_recorder: PlotDataRecorder): 31 ''' 32 Initializes the Evolution object with all of the protocols. 33 Does not execute any protocols 34 ''' 35 self.__gen_data_factory = gen_data_factory 36 self.__circuit_factory = circuit_factory 37 self.__reproduce = reproduce 38 self.__gen_init_populations = gen_init_populations 39 self.__eval_population_fitness = eval_population_fitness 40 self.__generate_measurements = generate_measurements 41 self.__hardware = hardware 42 self.__plot_data_recorder = plot_data_recorder
43
[docs] 44 def run(self): 45 ''' 46 Runs the desired experiment, based on the protocols provided 47 ''' 48 populations: list[Population] = self.__gen_init_populations() 49 gen_data = self.__gen_data_factory(None) 50 while gen_data is not None: 51 measurements = self.__generate_measurements(self.__circuit_factory, populations) 52 tasks = [self.__hardware.request_measurement(m) for m in measurements] 53 # asyncio.gather dispatches all measurement requests concurrently. In the intended 54 # server-client model, each await genuinely suspends while waiting for a network 55 # response, so multiple FPGAs are measured in parallel here. 56 # NOTE: asyncio.run() creates a new event loop each generation and destroys it 57 # after. A cleaner approach is to make run() itself async (i.e. `async def run`) 58 # and use `await asyncio.gather(*tasks)` directly, keeping one event loop for the 59 # whole experiment. See .claude/docs/hardware_concurrency.md for discussion. 60 results = asyncio.run( asyncio.gather(*tasks) ) 61 62 for p in populations: 63 self.__eval_population_fitness(p, results) 64 populations = list(map(lambda p: self.__reproduce(p), populations)) 65 66 fits: list[float] = [] 67 for p in populations: 68 for (i, f) in p: 69 fits.append(f) # type: ignore 70 # TODO: calculate diversity 71 self.__plot_data_recorder.record_generation(fits, gen_data.generation_number, 0) 72 73 gen_data = self.__gen_data_factory(gen_data)