From b92e1bc1a16d8fb947fe81553f7c3aa12a49c800 Mon Sep 17 00:00:00 2001 From: Oskar Taubert Date: Wed, 18 Sep 2024 10:13:12 +0200 Subject: [PATCH] simplified _get_active_individuals method --- propulate/migrator.py | 14 +++++++------- propulate/pollinator.py | 12 ++++++------ propulate/propulator.py | 21 ++++++++++----------- tests/test_island.py | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/propulate/migrator.py b/propulate/migrator.py index 8e10b6c..c946f1f 100644 --- a/propulate/migrator.py +++ b/propulate/migrator.py @@ -177,6 +177,7 @@ def _send_emigrants(self, hdf5_checkpoint: h5py.File) -> None: # NOTE Determine new responsible worker on target island. ind.current = self.rng.randrange(0, count) # NOTE activate on target island in checkpoint + # NOTE this happens here, so that if the message does not arrive, individuals are still loaded on an island from the checkpoint hdf5_checkpoint[f"{ind.island}"][f"{ind.island_rank}"]["active_on_island"][ind.generation, target_island] = True # TODO isnt the same set of individuals sent to all islands here? @@ -200,14 +201,14 @@ def _send_emigrants(self, hdf5_checkpoint: h5py.File) -> None: ] # TODO move this to a test assert len(to_deactivate) == 1 # There should be exactly one! - _, n_active_before = self._get_active_individuals() + n_active_before = len(self._get_active_individuals()) self.population[to_deactivate[0]].active = False # Deactivate emigrant in population. - _, n_active_after = self._get_active_individuals() + n_active_after = len(self._get_active_individuals()) log_string += ( f"Deactivated own emigrant {self.population[to_deactivate[0]]}. " + f"Active before/after: {n_active_before}/{n_active_after}\n" ) - _, n_active = self._get_active_individuals() + n_active = len(self._get_active_individuals()) log_string += f"After emigration: {n_active}/{len(self.population)} active.\n" log.debug(log_string) @@ -264,7 +265,7 @@ def _receive_immigrants(self) -> None: # NOTE Do not remove obsolete individuals from population upon immigration # as they should be deactivated in the next step anyway. - _, n_active = self._get_active_individuals() + n_active = len(self._get_active_individuals()) log_string += f"After immigration: {n_active}/{len(self.population)} active.\n" log.debug(log_string) @@ -351,7 +352,7 @@ def _deactivate_emigrants(self) -> None: log_string += ( f"Deactivated {self.population[to_deactivate[0]]}.\n" + f"{len(self.emigrated)} individuals in emigrated.\n" ) - _, n_active = self._get_active_individuals() + n_active = len(self._get_active_individuals()) log_string += ( "After synchronization: " + f"{n_active}/{len(self.population)} active.\n" @@ -478,8 +479,7 @@ def propulate(self, logging_interval: int = 10, debug: int = 1) -> None: if len(self.emigrated) > 0: log.info( f"Island {self.island_idx} Worker {self.island_comm.rank} Generation {self.generation}: " - f"Finally {len(self.emigrated)} individual(s) in emigrated: {self.emigrated}:\n" - f"{self.population}" + f"Finally {len(self.emigrated)} individual(s) in emigrated: {self.emigrated}" ) self._deactivate_emigrants() if self._check_emigrants_to_deactivate(): diff --git a/propulate/pollinator.py b/propulate/pollinator.py index fe80c4f..458af40 100644 --- a/propulate/pollinator.py +++ b/propulate/pollinator.py @@ -140,7 +140,7 @@ def _send_emigrants(self) -> None: # For pollination, an emigration-responsible worker is not necessary as emigrating individuals are not # deactivated and copies are allowed. # All active individuals are eligible emigrants. - eligible_emigrants, _ = self._get_active_individuals() + eligible_emigrants = self._get_active_individuals() # Only perform migration if maximum number of emigrants to be sent out at once is smaller than current number # of eligible emigrants. @@ -180,7 +180,7 @@ def _send_emigrants(self) -> None: f"on target island {target_island}.\n" ) - _, num_active = self._get_active_individuals() + num_active = len(self._get_active_individuals()) log_string += f"After emigration: {num_active}/{len(self.population)} active.\n" log.debug(log_string) @@ -251,7 +251,7 @@ def _receive_immigrants(self, hdf5_checkpoint: h5py.File) -> None: individual.generation, self.island_idx ] = False - _, num_active = self._get_active_individuals() + num_active = len(self._get_active_individuals()) log_string += f"After immigration: {num_active}/{len(self.population)} active." log.debug(log_string) @@ -286,17 +286,17 @@ def _deactivate_replaced_individuals(self) -> None: continue # NOTE As copies are allowed, len(to_deactivate) can be greater than 1. # However, only one of the copies should be replaced / deactivated. - _, num_active_before = self._get_active_individuals() + num_active_before = len(self._get_active_individuals()) self.population[to_deactivate[0]].active = False self.replaced.remove(individual) - _, num_active_after = self._get_active_individuals() + num_active_after = len(self._get_active_individuals()) log_string += ( f"Before deactivation: {num_active_before}/{len(self.population)} active.\n" f"Deactivated {self.population[to_deactivate[0]]}.\n" f"{len(self.replaced)} individuals in replaced.\n" f"After deactivation: {num_active_after}/{len(self.population)} active.\n" ) - _, num_active = self._get_active_individuals() + num_active = len(self._get_active_individuals()) log_string += ( f"After synchronization: {num_active}/{len(self.population)} active.\n" f"{len(self.replaced)} individuals in replaced.\n" diff --git a/propulate/propulator.py b/propulate/propulator.py index d663752..e22a933 100644 --- a/propulate/propulator.py +++ b/propulate/propulator.py @@ -346,7 +346,7 @@ def set_up_checkpoint(self) -> None: data=np.zeros((self.generations, num_islands), dtype=bool), ) - def _get_active_individuals(self) -> Tuple[List[Individual], int]: + def _get_active_individuals(self) -> List[Individual]: """ Get active individuals in current population list. @@ -358,8 +358,7 @@ def _get_active_individuals(self) -> Tuple[List[Individual], int]: The number of currently active individuals. """ active_pop = [ind for ind in self.population.values() if ind.active] - # TODO simplify - return active_pop, len(active_pop) + return active_pop def _breed(self) -> Individual: """ @@ -374,7 +373,7 @@ def _breed(self) -> Individual: self.propulate_comm is not None ): # Only processes in the Propulate world communicator, consisting of rank 0 of each worker's sub # communicator, are involved in the actual optimization routine. - active_pop, _ = self._get_active_individuals() + active_pop = self._get_active_individuals() ind = self.propagator(active_pop) # Breed new individual from active population. assert isinstance(ind, Individual) ind.generation = self.generation # Set generation. @@ -445,9 +444,9 @@ def loss_fn(individual: Individual) -> float: self.surrogate.update(ind.loss) if self.propulate_comm is None: return - self.population[(self.island_idx, self.island_comm.rank, ind.generation)] = ( - ind # Add evaluated individual to worker-local population. - ) + self.population[ + (self.island_idx, self.island_comm.rank, ind.generation) + ] = ind # Add evaluated individual to worker-local population. log.debug( f"Island {self.island_idx} Worker {self.island_comm.rank} Generation {self.generation}: BREEDING\n" f"Bred and evaluated individual {ind}." @@ -498,12 +497,12 @@ def _receive_intra_island_individuals(self) -> None: if SURROGATE_KEY in ind_temp: del ind_temp[SURROGATE_KEY] - self.population[(ind_temp.island, ind_temp.rank, ind_temp.generation)] = ( - ind_temp # Add received individual to own worker-local population. - ) + self.population[ + (ind_temp.island, ind_temp.rank, ind_temp.generation) + ] = ind_temp # Add received individual to own worker-local population. log_string += f"Added individual {ind_temp} from W{stat.Get_source()} to own population.\n" - _, n_active = self._get_active_individuals() + n_active = len(self._get_active_individuals()) log_string += f"After probing within island: {n_active}/{len(self.population)} active." log.debug(log_string) diff --git a/tests/test_island.py b/tests/test_island.py index c98bc2f..d43de13 100644 --- a/tests/test_island.py +++ b/tests/test_island.py @@ -176,7 +176,7 @@ def test_islands_checkpointing( # Run actual optimization. islands.propulate(debug=2) - old_population = copy.deepcopy(islands.propulator._get_active_individuals()[0]) + old_population = copy.deepcopy(islands.propulator._get_active_individuals()) del islands islands = Islands(