Source code for metaheuristic_designer.initializers.composite_initializer
from typing import Iterable, Optional
from copy import copy
import numpy as np
from ..initializer import Initializer
from ..encoding import Encoding
from ..population import Population
from ..utils import IntVector, RealVector, RNGLike, VectorLike
[docs]
class CompositeInitializer(Initializer):
def __init__(
self,
dimension: int,
initializers: Iterable[Initializer],
weights: Optional[RealVector] = None,
population_size: Optional[int] = None,
encoding: Encoding = None,
rng: Optional[RNGLike] = None,
):
if population_size is None:
population_size = initializers[0].population_size
super().__init__(dimension, population_size, encoding=encoding, rng=rng)
initializers = copy(initializers)
for inits in initializers:
inits.population_size = population_size
self.initializers = initializers
if weights is None:
weights = np.ones(len(initializers))
else:
weights = np.asarray(weights)
weights = weights / np.sum(weights)
self.weights = weights
[docs]
def generate_random(self) -> VectorLike:
"""Generate a random individual from one initializers chosen at random.
Returns
-------
VectorLike
A 1-D array generated by the fallback initializer.
"""
idx = self.rng.choice(len(self.initializers), p=self.weights)
return self.initializers[idx].generate_random()
[docs]
def generate_individual(self) -> VectorLike:
"""Generate an individual from one of the initializers chosen at random.
Returns
-------
ndarray
A 1-D array representing the individual.
"""
idx = self.rng.choice(len(self.initializers), p=self.weights)
return self.initializers[idx].generate_individual()
[docs]
def generate_population(self, n_individuals=None):
"""Generate a population from individuals chosen at random from the initializers.
Parameters
----------
objfunc: ObjectiveFunc
Objective function that will be propagated to each individual.
n_individual: int, optional
Number of individuals to generate
Returns
-------
generated_population: Population
Newly generated population.
"""
if n_individuals is None:
n_individuals = self.population_size
n_initializers = len(self.initializers)
# Generate all populations from which to choose
populations = [i.generate_population(n_individuals=n_individuals) for i in self.initializers]
# Randomly choose individuals from each population
population_tensor = np.asarray([p.genotype_matrix for p in populations])
choice_idx = self.rng.choice(n_initializers, n_individuals, p=self.weights)
chosen_population = population_tensor[choice_idx, np.arange(n_individuals), :]
return Population(genotype_matrix=chosen_population, encoding=self.encoding)
[docs]
class FixedCompositeInitializer(Initializer):
def __init__(
self,
dimension: int,
initializers: Iterable[Initializer],
amounts: Optional[IntVector] = None,
population_size: Optional[int] = None,
encoding: Encoding = None,
rng: Optional[RNGLike] = None,
):
if population_size is None:
population_size = np.sum(amounts)
super().__init__(dimension, population_size, encoding=encoding, rng=rng)
initializers = copy(initializers)
for inits in initializers:
inits.population_size = population_size
self.initializers = initializers
self.init_counter = 0
if amounts is None:
amounts = np.ones(len(initializers))
self.amounts = amounts
self._amounts_cumsum = np.cumsum(amounts)
[docs]
def generate_random(self) -> VectorLike:
"""Generate a random individual from one of the initializers chosen deterministically.
Returns
-------
VectorLike
A 1-D array generated by the fallback initializer.
"""
idx = np.searchsorted(self._amounts_cumsum, self.init_counter, side="right")
self.init_counter = (self.init_counter + 1) % np.sum(self.amounts)
return self.initializers[idx].generate_random()
[docs]
def generate_individual(self) -> VectorLike:
"""Generate an individual from one of the initializers chosen deterministically.
Returns
-------
ndarray
A 1-D array representing the individual.
"""
idx = np.searchsorted(self._amounts_cumsum, self.init_counter, side="right")
self.init_counter = (self.init_counter + 1) % np.sum(self.amounts)
return self.initializers[idx].generate_individual()
[docs]
def generate_population(self, n_individuals=None):
"""Generate a population from individuals chosen at random from the initializers.
Parameters
----------
objfunc: ObjectiveFunc
Objective function that will be propagated to each individual.
n_individual: int, optional
Number of individuals to generate
Returns
-------
generated_population: Population
Newly generated population.
"""
if n_individuals is None:
n_individuals = self.population_size
n_initializers = len(self.initializers)
# Generate all populations from which to choose
populations = [i.generate_population(n_individuals=n_individuals) for i in self.initializers]
# Choose individuals as indicated by the amount attribute
population_tensor = np.asarray([p.genotype_matrix for p in populations])
cyclic_amounts = np.repeat(np.arange(n_initializers), self.amounts)
choice_idx = np.resize(cyclic_amounts, n_individuals)
chosen_population = population_tensor[choice_idx, np.arange(n_individuals), :]
return Population(genotype_matrix=chosen_population, encoding=self.encoding)