Source code for metaheuristic_designer.initializers.halton_initializer
"""Initializer that implements Halton sequences as an initialization technique."""
from __future__ import annotations
from typing import Optional
import numpy as np
import scipy as sp
from ..objective_function import ObjectiveFunc
from ..population import Population
from .uniform_initializer import UniformInitializer
from ..initializer import Initializer
[docs]
class HaltonInitializer(Initializer):
"""
Initializer that generates individuals using the Halton sequences,
this is a pseudo-random method designed for covering the space
efficiently.
Parameters
----------
dimension : int
Length of the genotype vector.
lower_bound : float or array
Lower bound(s) of the distribution. If an array is given,
it must have length `dimension`.
upper_bound : float or array
Upper bound(s) of the distribution. Must match the shape
of `lower_bound`.
population_size : int, optional
Number of individuals to generate (default 1).
encoding : Encoding, optional
Encoding that will be passed to each individual.
dtype : type, optional
Desired NumPy dtype of the generated vectors (default ``float``).
rng : RNGLike, optional
Random number generator.
"""
def __init__(
self,
dimension,
lower_bound,
upper_bound,
population_size=1,
scramble=True,
fallback: Optional[Initializer] = None,
encoding=None,
dtype=float,
rng=None,
):
super().__init__(dimension=dimension, population_size=population_size, encoding=encoding, rng=rng)
self.dtype = dtype
if type(lower_bound) in [list, tuple, np.ndarray]:
if len(lower_bound) != dimension:
raise ValueError(f"If lower_bound is a sequence it must be of length {dimension}.")
self.lower_bound = lower_bound
else:
self.lower_bound = np.repeat(lower_bound, self.dimension)
if type(upper_bound) in [list, tuple, np.ndarray]:
if len(upper_bound) != dimension:
raise ValueError(f"If upper_bound is a sequence it must be of length {dimension}.")
self.upper_bound = upper_bound
else:
self.upper_bound = np.repeat(upper_bound, self.dimension)
if fallback is None:
fallback = UniformInitializer(dimension, lower_bound, upper_bound, dtype=dtype, rng=rng)
self.fallback = fallback
self.scramble = scramble
[docs]
def generate_random(self):
return self.fallback.generate_random()
[docs]
def generate_population(self, n_individuals: Optional[int] = None) -> Population:
"""
Create a fully formed population of *n_individuals* individuals.
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
generator = sp.stats.qmc.Halton(d=self.dimension, scramble=self.scramble, rng=self.rng)
samples = generator.random(n_individuals)
population_matrix = (self.upper_bound - self.lower_bound) * samples + self.lower_bound
return Population(genotype_matrix=population_matrix, encoding=self.encoding)