Source code for metaheuristic_designer.constraint_handler

"""
Base class for the Constraint Handler module.

This module implements ways to enforce constraints on the objective function.
"""

from __future__ import annotations
from copy import copy
from typing import Any, Callable, Iterable, Optional
from abc import ABC, abstractmethod
from .parametrizable_mixin import ParametrizableMixin
from .utils import ScalarLike, VectorLike, MatrixLike


[docs] class ConstraintHandler(ParametrizableMixin, ABC): """Abstract base for all constraint handlers. A constraint handler can **repair** solutions (make them feasible) and/or compute a **penalty** that is subtracted from the objective value. Subclasses must implement at least one of these operations. Parameters ---------- encoding : Encoding, optional An :class:`Encoding` that will be used to extract the genotype before repair or penalty (default ``None``). **kwargs Additional keyword arguments stored as schedulable parameters. """ def __init__(self, encoding=None, **kwargs): super().__init__() self.encoding = encoding self.store_kwargs(**kwargs)
[docs] @abstractmethod def repair_solution(self, population_matrix: MatrixLike) -> MatrixLike: """ Modifies the incoming solution so that it follows the problem's constraints. Parameters ---------- solution: Any The input solution. Returns ------- fixed_solution: Any Modified version of the input solution that fits the problem's constraints """
[docs] @abstractmethod def penalty(self, population_matrix: MatrixLike) -> VectorLike: """ Offset to the objective value for the solution corresponding to violations of the problem's constraints. Parameters ---------- solution: Any The input solution. Returns ------- penalty: float The amount of penalty to apply to the current solution. """
[docs] def get_state(self): data = { "class_name": self.__class__.__name__, } return data
[docs] class ConstraintHandlerFromLambda(ConstraintHandler): """Constraint handler built from plain callables. At least one of *repair_solution_fn* or *penalty_fn* must be given. Parameters ---------- repair_solution_fn : callable, optional A function ``(solution) -> repaired_solution``. penalty_fn : callable, optional A function ``(solution) -> penalty_value``. **kwargs Keyword arguments forwarded to :class:`ConstraintHandler`. """ def __init__(self, repair_solution_fn: Optional[Callable] = None, penalty_fn: Optional[Callable] = None, **kwargs): super().__init__(**kwargs) if repair_solution_fn is None and penalty_fn is None: raise ValueError("You must give the implementation of the repairing procedure or the penalty calculation.") self.repair_solution_fn = repair_solution_fn self.penalty_fn = penalty_fn
[docs] def repair_solution(self, solution: Iterable) -> Iterable: if self.repair_solution_fn is None: return copy(solution) return self.repair_solution_fn(solution)
[docs] def penalty(self, solution: Any) -> ScalarLike: if self.penalty_fn is None: return 0 return self.penalty_fn(solution)
[docs] class NullConstraint(ConstraintHandler): """Constraint handler that enforces no restrictions. The penalty is always zero, and repairing returns the solution unchanged. Parameters ---------- encoding : Encoding, optional See :class:`ConstraintHandler`. **kwargs See :class:`ConstraintHandler`. """
[docs] def repair_solution(self, solution: MatrixLike) -> MatrixLike: return copy(solution)
[docs] def penalty(self, _solution: Any) -> ScalarLike: return 0
[docs] class PenalizeConstraint(ConstraintHandler, ABC): """Abstract handler that only computes penalties. Repairing does nothing (returns a copy). Subclasses must override :meth:`penalty`. Parameters ---------- encoding : Encoding, optional See :class:`ConstraintHandler`. **kwargs See :class:`ConstraintHandler`. """
[docs] def repair_solution(self, solution: Iterable) -> Iterable: return copy(solution)
[docs] class RepairConstraint(ConstraintHandler, ABC): """Abstract handler that only repairs solutions. The penalty is always zero. Subclasses must override :meth:`repair_solution`. Parameters ---------- encoding : Encoding, optional See :class:`ConstraintHandler`. **kwargs See :class:`ConstraintHandler`. """
[docs] def penalty(self, _solution: Iterable) -> VectorLike: return 0