Source code for metaheuristic_designer.initializer

"""
Base class for the Initializer module.

This module implements functions to generate the initial population of the algorithm.
"""

from __future__ import annotations
from typing import Any, Optional, Callable
from abc import ABC, abstractmethod
import numpy as np
from .population import Population
from .encoding import Encoding, DefaultEncoding
from .objective_function import ObjectiveFunc
from .utils import check_random_state, RNGLike, VectorLike


[docs] class Initializer(ABC): """Abstract base for all population initializers. An initializer creates the first generation of individuals. It must provide a way to generate a single random genotype vector (a 1-D NumPy array) via :meth:`generate_random` and can optionally wrap it with a different definition of an individual via :meth:`generate_individual`. Parameters ---------- dimension : int Length of the genotype vector. population_size : int, optional Number of individuals to generate (default 1). encoding : Encoding, optional Encoding that will be attached to every individual. Defaults to :class:`DefaultEncoding`. random_state : RNGLike, optional Random number generator. """ def __init__(self, dimension: int, population_size: int = 1, encoding: Optional[Encoding] = None, random_state: Optional[RNGLike] = None): self.dimension = dimension self.population_size = population_size if encoding is None: encoding = DefaultEncoding() self.encoding = encoding self.random_state = check_random_state(random_state)
[docs] @abstractmethod def generate_random(self) -> VectorLike: """Generate a single random genotype vector (1-D array). Returns ------- VectorLike A newly generated genotype vector (1-D array). """
[docs] def generate_individual(self) -> VectorLike: """Generate a single individual. By default simply delegates to :meth:`generate_random`. Returns a newly generated individual (a 1-D array). Override this method if your initializer needs to distinguish between a randomly initialize individual and a solution generated with another strategy (See `SeedProbInitializer`). Returns ------- Any A newly generated individual. """ return self.generate_random()
[docs] def generate_population(self, objfunc: ObjectiveFunc, 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 population_matrix = np.asarray([self.generate_individual() for _ in range(n_individuals)]) return Population(objfunc, genotype_matrix=population_matrix, encoding=self.encoding)
[docs] def get_state(self) -> dict: """Return a minimal dictionary identifying this initializer. Returns ------- dict Dictionary with key ``"class_name"``. """ data = {"class_name": self.__class__.__name__} return data
[docs] class InitializerFromLambda(Initializer): """Initializer that uses a user-provided function to generate individuals. Parameters ---------- generator : callable A function ``(random_state) -> genotype`` that returns a single genotype vector. dimension : int Length of the genotype vector. pop_size : int, optional Number of individuals to generate (default 1). encoding : Encoding, optional Encoding attached to every individual. random_state : RNGLike, optional Random number generator. """ def __init__( self, generator: Callable, dimension: int, pop_size: int = 1, encoding: Optional[Encoding] = None, random_state: Optional[RNGLike] = None ): self.generator = generator super().__init__(dimension=dimension, population_size=pop_size, encoding=encoding, random_state=random_state)
[docs] def generate_random(self) -> VectorLike: return self.generator(self.random_state)