[1190] | 1 | import time |
---|
| 2 | from abc import ABC |
---|
| 3 | from typing import List |
---|
| 4 | |
---|
| 5 | from ..structures.individual import Individual |
---|
| 6 | from ..structures.population import PopulationStructures |
---|
| 7 | from .experiment_abc import ExperimentABC |
---|
| 8 | |
---|
| 9 | |
---|
| 10 | class ExperimentIslands(ExperimentABC, ABC): |
---|
| 11 | |
---|
| 12 | def __init__(self, popsize, hof_size, number_of_populations, migration_interval, save_only_best) -> None: |
---|
| 13 | super().__init__(popsize=popsize, hof_size=hof_size, save_only_best=save_only_best) |
---|
[1294] | 14 | self.populations=[] |
---|
[1190] | 15 | self.number_of_populations=number_of_populations |
---|
| 16 | self.migration_interval=migration_interval |
---|
| 17 | |
---|
| 18 | def migrate_populations(self): |
---|
| 19 | print("Performing base migration") |
---|
| 20 | pool_of_all_individuals = [] |
---|
| 21 | for p in self.populations: |
---|
| 22 | pool_of_all_individuals.extend(p.population) |
---|
| 23 | print(f"Pool of individuals: {len(pool_of_all_individuals)}") |
---|
| 24 | sorted_individuals = sorted( |
---|
| 25 | pool_of_all_individuals, key=lambda x: x.rawfitness) |
---|
[1291] | 26 | print("Best individual for new islands:") |
---|
[1190] | 27 | for i in range(self.number_of_populations): |
---|
| 28 | shift = i*self.popsize |
---|
| 29 | self.populations[i].population = sorted_individuals[shift:shift+self.popsize] |
---|
| 30 | print(i, self.populations[i].population[-1].rawfitness) |
---|
| 31 | |
---|
| 32 | def initialize_evolution(self, initialgenotype): |
---|
| 33 | self.current_generation = 0 |
---|
| 34 | self.time_elapsed = 0 |
---|
| 35 | self.stats = [] # stores the best individuals, one from each generation |
---|
| 36 | initial_individual = Individual() |
---|
| 37 | initial_individual.set_and_evaluate(initialgenotype, self.evaluate) |
---|
| 38 | self.stats.append(initial_individual.rawfitness) |
---|
| 39 | [self.populations.append(PopulationStructures(initial_individual=initial_individual, |
---|
| 40 | popsize=self.popsize)) |
---|
| 41 | for _ in range(self.number_of_populations)] |
---|
| 42 | |
---|
| 43 | def get_state(self): |
---|
| 44 | return [self.time_elapsed, self.current_generation, self.populations, self.hof, self.stats] |
---|
| 45 | |
---|
| 46 | def set_state(self, state): |
---|
| 47 | self.time_elapsed, self.current_generation, self.populations, hof_, self.stats = state |
---|
| 48 | # sorting: ensure that we add from worst to best so all individuals are added to HOF |
---|
| 49 | for h in sorted(hof_, key=lambda x: x.rawfitness): |
---|
| 50 | self.hof.add(h) |
---|
| 51 | |
---|
| 52 | def evolve(self, hof_savefile, generations, initialgenotype, pmut, pxov, tournament_size): |
---|
| 53 | file_name = self.get_state_filename(hof_savefile) |
---|
| 54 | state = self.load_state(file_name) |
---|
| 55 | if state is not None: # loaded state from file |
---|
| 56 | # saved generation has been completed, start with the next one |
---|
| 57 | self.current_generation += 1 |
---|
| 58 | print("...Resuming from saved state: population size = %d, hof size = %d, stats size = %d, generation = %d/%d" % (len(self.populations[0].population), len( |
---|
| 59 | self.hof), len(self.stats), self.current_generation, generations)) # self.current_generation (and g) are 0-based, parsed_args.generations is 1-based |
---|
| 60 | else: |
---|
| 61 | self.initialize_evolution(initialgenotype) |
---|
| 62 | time0 = time.process_time() |
---|
| 63 | for g in range(self.current_generation, generations): |
---|
| 64 | for p in self.populations: |
---|
| 65 | p.population = self.make_new_population( |
---|
| 66 | p.population, pmut, pxov, tournament_size) |
---|
| 67 | |
---|
| 68 | if g % self.migration_interval == 0: |
---|
| 69 | print("---------Start of migration-------") |
---|
| 70 | self.migrate_populations() |
---|
| 71 | print("---------End of migration---------") |
---|
| 72 | |
---|
| 73 | pool_of_all_individuals = [] |
---|
| 74 | [pool_of_all_individuals.extend(p.population) |
---|
| 75 | for p in self.populations] |
---|
| 76 | self.update_stats(g, pool_of_all_individuals) |
---|
| 77 | if hof_savefile is not None: |
---|
| 78 | self.current_generation = g |
---|
| 79 | self.time_elapsed += time.process_time() - time0 |
---|
| 80 | self.save_state(file_name) |
---|
| 81 | |
---|
| 82 | if hof_savefile is not None: |
---|
| 83 | self.save_genotypes(hof_savefile) |
---|
| 84 | |
---|
| 85 | return self.hof, self.stats |
---|
| 86 | |
---|
| 87 | @staticmethod |
---|
| 88 | def get_args_for_parser(): |
---|
| 89 | parser = ExperimentABC.get_args_for_parser() |
---|
| 90 | |
---|
| 91 | parser.add_argument("-islands",type=int, default=5, |
---|
| 92 | help="Number of subpopulations (islands)") |
---|
| 93 | parser.add_argument("-generations_migration",type=int, default=10, |
---|
| 94 | help="Number of generations separating migration events when genotypes migrate between subpopulations (islands)") |
---|
| 95 | return parser |
---|