Source code for cvxpy.constraints.constraint

"""
Copyright 2013 Steven Diamond

This file is part of CVXPY.

CVXPY is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

CVXPY is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with CVXPY.  If not, see <http://www.gnu.org/licenses/>.
"""

import cvxpy.utilities as u
import cvxpy.lin_ops.lin_utils as lu
from cvxpy.expressions import cvxtypes
import abc
import numpy as np


[docs]class Constraint(u.Canonical): """The base class for constraints. A constraint is an equality, inequality, or more generally a generalized inequality that is imposed upon a mathematical expression or a list of thereof. Parameters ---------- args : list A list of expression trees. constr_id : int A unique id for the constraint. """ __metaclass__ = abc.ABCMeta def __init__(self, args, constr_id=None): # TODO cast constants. # self.args = [cvxtypes.expression().cast_to_const(arg) for arg in args] self.args = args if constr_id is None: self.constr_id = lu.get_id() else: self.constr_id = constr_id self.dual_variables = [cvxtypes.variable()(arg.shape) for arg in args] super(Constraint, self).__init__() def __str__(self): """Returns a string showing the mathematical constraint. """ return self.name() def __repr__(self): """Returns a string with information about the constraint. """ return "%s(%s)" % (self.__class__.__name__, repr(self.args[0])) @property def shape(self): """int : The shape of the constrained expression.""" return self.args[0].shape @property def size(self): """int : The size of the constrained expression.""" return self.args[0].size def is_real(self): """Is the Leaf real valued? """ return not self.is_complex() def is_imag(self): """Is the Leaf imaginary? """ return all(arg.is_imag() for arg in self.args) def is_complex(self): """Is the Leaf complex valued? """ return any(arg.is_complex() for arg in self.args)
[docs] @abc.abstractmethod def is_dcp(self): """Checks whether the constraint is DCP. Returns ------- bool True if the constraint is DCP, False otherwise. """ return NotImplemented
@abc.abstractproperty def residual(self): """The residual of the constraint. Returns ------- NumPy.ndarray The residual, or None if the constrained expression does not have a value. """ return NotImplemented
[docs] def violation(self): """The numeric residual of the constraint. The violation is defined as the distance between the constrained expression's value and its projection onto the domain of the constraint: .. math:: ||\Pi(v) - v||_2^2 where :math:`v` is the value of the constrained expression and :math:`\\Pi` is the projection operator onto the constraint's domain . Returns ------- NumPy.ndarray The residual value. Raises ------ ValueError If the constrained expression does not have a value associated with it. """ residual = self.residual if residual is None: raise ValueError("Cannot compute the violation of an constraint " "whose expression is None-valued.") return residual
[docs] def value(self, tolerance=1e-8): """Checks whether the constraint violation is less than a tolerance. Parameters ---------- tolerance : float The absolute tolerance to impose on the violation. Returns ------- bool True if the violation is less than ``tolerance``, False otherwise. Raises ------ ValueError If the constrained expression does not have a value associated with it. """ residual = self.residual if residual is None: raise ValueError("Cannot compute the value of an constraint " "whose expression is None-valued.") return np.all(residual <= tolerance)
@property def id(self): """Wrapper for compatibility with variables. """ return self.constr_id def get_data(self): """Data needed to copy. """ return [self.id] def __nonzero__(self): """Raises an exception when called. Python 2 version. Called when evaluating the truth value of the constraint. Raising an error here prevents writing chained constraints. """ return self._chain_constraints() def _chain_constraints(self): """Raises an error due to chained constraints. """ raise Exception( ("Cannot evaluate the truth value of a constraint or " "chain constraints, e.g., 1 >= x >= 0.") ) def __bool__(self): """Raises an exception when called. Python 3 version. Called when evaluating the truth value of the constraint. Raising an error here prevents writing chained constraints. """ return self._chain_constraints() # The value of the dual variable. @property def dual_value(self): """NumPy.ndarray : The value of the dual variable. """ return self.dual_variables[0].value # TODO(akshayka): Rename to save_dual_value to avoid collision with # value as defined above. def save_value(self, value): """Save the value of the dual variable for the constraint's parent. Args: value: The value of the dual variable. """ self.dual_variables[0].save_value(value)