Source code for metaheuristic_designer.constraint_handlers.bounce_bound_constraint
from __future__ import annotations
from copy import copy
import numpy as np
from ..constraint_handler import RepairConstraint
from ..utils import MatrixLike, ScalarLike, VectorLike
[docs]
class BounceBoundConstraint(RepairConstraint):
"""
Encodes a bound constraint by bouncing through the bounds, substracting the leftover part of the vector
that lies outisde the bounds. If the substraction still lies outside the bounds, the leftover part is added,
substraction and addition are alternated until the solution lies in bounds.
Parameters
----------
dimension: int
size of the input vector (decoded).
lower_bound: float | ndarray, optional
lower limit of the bounds.
upper_bound: float | ndarray, optional
upper limit of the bounds.
"""
def __init__(self, dimension, lower_bound: ScalarLike | VectorLike = -100, upper_bound: ScalarLike | VectorLike = 100, **kwargs):
self.dimension = dimension
self.lower_bound = np.asarray(lower_bound)
self.upper_bound = np.asarray(upper_bound)
self.range_lim = self.upper_bound - self.lower_bound
super().__init__(**kwargs)
[docs]
def repair_solution(self, population_matrix: MatrixLike) -> MatrixLike:
if np.all(self.upper_bound == self.lower_bound):
if self.upper_bound.ndim == 0:
return np.full_like(population_matrix, self.upper_bound)
return np.tile(self.upper_bound, (population_matrix.shape[0], 1))
shifted_vector = population_matrix - self.lower_bound
bounce_times = np.floor_divide(shifted_vector, self.range_lim)
fixed_solution = np.mod((-1.0) ** bounce_times * shifted_vector, self.range_lim) + self.lower_bound
ouside_bound_mask = (population_matrix < self.lower_bound) | (population_matrix > self.upper_bound)
population_matrix = copy(population_matrix)
population_matrix[ouside_bound_mask] = fixed_solution[ouside_bound_mask]
return population_matrix