Source code for flopt.constraint

from flopt.constants import ConstraintType, number_classes
from flopt.env import setup_logger, create_variable_mode

logger = setup_logger(__name__)


[docs]class Constraint: """Constraint Class three type constraint, == or <= - eq type (equal) expression == 0 - le type (less than or equal) expression <= 0 Parameters ---------- expression : Expression family expression of constraint. type : ConstraintType Constraint type (Eq or Le) Notes ----- For some types, the constraint class may not be created if the constant is placed on the left side. .. code-block:: python import flopt import numpy as np a = flopt.Variable('a', cat='Binary') np.float64(0) <= a >>> True a >= np.float64(0) >>> Constraint(Expression(-1, a, *), Le, None) """ def __init__(self, expression, _type, name=None): assert isinstance(_type, ConstraintType) self.expression = expression self._type = _type self.name = name self.hash = None
[docs] def clone(self): """ Returns ------- Reduction """ return Constraint(self.expression.clone(), self._type, self.name)
def type(self): return self._type def value(self, solution=None): return self.expression.value(solution) def feasible(self, solution=None): exp_value = self.value(solution) if self._type == ConstraintType.Eq: return exp_value == 0 # self._type == ConstraintType.Le return exp_value <= 0 def getVariables(self): return self.expression.getVariables() def isLinear(self): return self.expression.isLinear() def toSpin(self): self.expression = self.expression.toSpin() return self def __rshift__(self, other): """If self is satisfied, then other must be satisfied .. code-block:: python import flopt x = flopt.Variable("x", lowBound=0, upBound=10) prob = flopt.Problem() # if x is less or equal than 3, then x must be 0 prob += (x <= 3) >> (x == 0) """ assert isinstance(other, Constraint) import flopt epsilon = 1e-5 slide_epsilon = 0.1 * epsilon def sazp(v): """Slide value for Avoiding Zero in pulus direction""" if v != 0: return v return vv if (vv := v + slide_epsilon) != 0 else vv + slide_epsilon def sazm(v): """Slide value for Avoiding Zero in minus direction""" if v != 0: return v return vv if (vv := v - slide_epsilon) != 0 else vv - slide_epsilon constraints = [] x = self.expression y = other.expression with create_variable_mode(): delta = flopt.Variable(f"delta", cat="Binary") constraints += [sazm(x.min()) * delta <= x - epsilon] if self.type() == ConstraintType.Le: indicator = delta if self.type() == ConstraintType.Eq: with create_variable_mode(): theta = flopt.Variable(f"theta", cat="Binary") sigma = flopt.Variable(f"sigma", cat="Binary") constraints += [sazp(x.max()) * theta <= x + epsilon] constraints += [sigma >= theta + delta - 1] indicator = sigma constraints += [y <= sazp(y.max()) * (1 - indicator)] if other.type() == ConstraintType.Eq: constraints += [y >= sazm(y.min()) * (1 - indicator)] return constraints def __hash__(self): if self.hash is None: self.hash = hash((Constraint, hash(self.expression), self._type)) return self.hash def __eq__(self, other): return hash(self) == hash(other) def __str__(self): if self._type == ConstraintType.Eq: type_str = "==" else: # self._type == ConstraintType.Le type_str = "<=" return f"{self.expression.getName()} {type_str} 0" def __repr__(self): return f"Constraint({self.expression!r}, {self._type}, {self.name})"