Source code for iwopy.core.constraint

import numpy as np

from iwopy.utils import new_instance
from .function import OptFunction


[docs] class Constraint(OptFunction): """ Abstract base class for optimization constraints. Attributes ---------- tol: float The tolerance for constraint violations :group: core """
[docs] def __init__(self, *args, tol=1e-5, **kwargs): """ Constructor Parameters ---------- tol: float The tolerance for constraint violations """ super().__init__(*args, **kwargs) self.tol = tol
[docs] def get_bounds(self): """ Returns the bounds for all components. Non-existing bounds are expressed by np.inf. Returns ------- min: np.array The lower bounds, shape: (n_components,) max: np.array The upper bounds, shape: (n_components,) """ return ( np.full(self.n_components(), -np.inf, dtype=np.float64), np.zeros(self.n_components(), dtype=np.float64), )
[docs] def check_individual(self, constraint_values, verbosity=0): """ Check if the constraints are fullfilled for the given individual. Parameters ---------- constraint_values: np.array The constraint values, shape: (n_components,) verbosity: int The verbosity level, 0 = silent Returns values: np.array ------- The boolean result, shape: (n_components,) """ vals = constraint_values mi, ma = self.get_bounds() out = (vals + self.tol >= mi) & (vals - self.tol <= ma) if verbosity: print(f"Constraint '{self.name}': tol = {self.tol}") cnames = self.component_names for ci in range(self.n_components()): val = f"{cnames[ci]} = {vals[ci]:.3e}" suc = "OK" if out[ci] else "FAILED" print(f" Constraint {val:<30} {suc}") return out
[docs] def check_population(self, constraint_values, verbosity=0): """ Check if the constraints are fullfilled for the given population. Parameters ---------- constraint_values: np.array The constraint values, shape: (n_pop, n_components,) verbosity: int The verbosity level, 0 = silent Returns ------- values: np.array The boolean result, shape: (n_pop, n_components) """ vals = constraint_values mi, ma = self.get_bounds() mi = np.array(mi, dtype=np.float64) ma = np.array(ma, dtype=np.float64) out = (vals + self.tol >= mi[None, :]) & (vals - self.tol <= ma[None, :]) if verbosity: print(f"Constraint '{self.name}': tol = {self.tol}") cnames = self.component_names for ci in range(self.n_components()): suc = "OK" if np.all(out[ci]) else "FAILED" print(f" Constraint {cnames[ci]:<20} {suc}") return out
[docs] @classmethod def new(cls, constraint_type, *args, **kwargs): """ Run-time constraint factory. Parameters ---------- constraint_type: str The selected derived class name args: tuple, optional Additional parameters for constructor kwargs: dict, optional Additional parameters for constructor """ return new_instance(cls, constraint_type, *args, **kwargs)