Source code for cvxpy.constraints.psd

"""
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.settings as s
import cvxpy.lin_ops.lin_utils as lu
import cvxpy.utilities.performance_utils as pu
from cvxpy.expressions import cvxtypes
from cvxpy.constraints.constraint import Constraint


[docs]class PSD(Constraint): """A constraint of the form :math:`\\frac{1}{2}(X + X^T) \succcurlyeq_{S_n^+} 0` Applying a ``PSD`` constraint to a two-dimensional expression ``X`` constrains its symmetric part to be positive semidefinite: i.e., it constrains ``X`` to be such that .. math:: z^T(X + X^T)z \geq 0, for all :math:`z`. The preferred way of creating a ``PSD`` constraint is through operator overloading. To constrain an expression ``X`` to be PSD, write ``X >> 0``; to constrain it to be negative semidefinite, write ``X << 0``. Strict definiteness constraints are not provided, as they do not make sense in a numerical setting. Parameters ---------- expr : Expression. The expression to constrain; *must* be two-dimensional. constr_id : int A unique id for the constraint. """ def __init__(self, expr, constr_id=None): # Argument must be square matrix. if len(expr.shape) != 2 or expr.shape[0] != expr.shape[1]: raise ValueError( "Non-square matrix in positive definite constraint." ) super(PSD, self).__init__([expr], constr_id) def name(self): return "%s >> 0" % self.args[0]
[docs] def is_dcp(self): """A PSD constraint is DCP if the constrained expression is affine. """ return self.args[0].is_affine()
@property def residual(self): """The residual of the constraint. Returns ------- NumPy.ndarray """ if self.expr.value is None: return None min_eig = cvxtypes.lambda_min()(self.args[0] + self.args[0].T)/2 return cvxtypes.neg()(min_eig).value def canonicalize(self): """Returns the graph implementation of the object. Marks the top level constraint as the dual_holder, so the dual value will be saved to the Zero. Returns: A tuple of (affine expression, [constraints]). """ obj, constraints = self.args[0].canonical_form dual_holder = PSD(obj, constr_id=self.id) return (None, constraints + [dual_holder]) def format(self, eq_constr, leq_constr, dims, solver): """Formats PSD constraints as inequalities for the solver. Parameters ---------- eq_constr : list A list of the equality constraints in the canonical problem. leq_constr : list A list of the inequality constraints in the canonical problem. dims : dict A dict with the dimensions of the conic constraints. solver : str The solver being called. """ new_leq_constr = self.__format # 0 <= A leq_constr += new_leq_constr # Update dims. dims[s.PSD_DIM].append(self.shape[0]) @pu.lazyprop def __format(self): """Internal version of format with cached results. Returns ------- tuple (equality constraints, inequality constraints) """ leq_constr = lu.create_geq(self.expr, constr_id=self.constr_id) return [leq_constr]