Coverage for picos/constraints/con_rsoc.py: 92.00%
50 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-26 07:46 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-26 07:46 +0000
1# ------------------------------------------------------------------------------
2# Copyright (C) 2018-2019 Maximilian Stahlberg
3#
4# This file is part of PICOS.
5#
6# PICOS is free software: you can redistribute it and/or modify it under the
7# terms of the GNU General Public License as published by the Free Software
8# Foundation, either version 3 of the License, or (at your option) any later
9# version.
10#
11# PICOS is distributed in the hope that it will be useful, but WITHOUT ANY
12# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along with
16# this program. If not, see <http://www.gnu.org/licenses/>.
17# ------------------------------------------------------------------------------
19"""Rotated second order cone constraints."""
21from collections import namedtuple
23from .. import glyphs
24from ..apidoc import api_end, api_start
25from ..caching import cached_property
26from .constraint import ConicConstraint
28_API_START = api_start(globals())
29# -------------------------------
32class RSOCConstraint(ConicConstraint):
33 """Rotated second order cone membership constraint."""
35 def __init__(self, normedExpression, upperBoundFactor1,
36 upperBoundFactor2=None, customString=None):
37 """Construct a :class:`RSOCConstraint`.
39 :param ~picos.expressions.AffineExpression normedExpression:
40 Expression under the norm.
41 :param ~picos.expressions.AffineExpression upperBoundFactor1:
42 First of the two scalar factors that make the upper bound on the
43 normed expression.
44 :param ~picos.expressions.AffineExpression upperBoundFactor2:
45 Second of the two scalar factors that make the upper bound on the
46 normed expression.
47 :param str customString:
48 Optional string description.
49 """
50 from ..expressions import AffineExpression
52 if upperBoundFactor2 is None:
53 upperBoundFactor2 = AffineExpression.from_constant(1)
55 assert isinstance(normedExpression, AffineExpression)
56 assert isinstance(upperBoundFactor1, AffineExpression)
57 assert isinstance(upperBoundFactor2, AffineExpression)
58 assert len(upperBoundFactor1) == 1
59 assert len(upperBoundFactor2) == 1
61 self.ne = normedExpression
62 self.ub1 = upperBoundFactor1
63 self.ub2 = upperBoundFactor2
65 super(RSOCConstraint, self).__init__(
66 self._get_type_term(), customString, printSize=True)
68 def _get_type_term(self):
69 return "RSOC"
71 @cached_property
72 def conic_membership_form(self):
73 """Implement for :class:`~.constraint.ConicConstraint`."""
74 from ..expressions import RotatedSecondOrderCone
75 return (self.ub1 // self.ub2 // self.ne.vec), \
76 RotatedSecondOrderCone(dim=(len(self.ne) + 2))
78 Subtype = namedtuple("Subtype", ("argdim",))
80 def _subtype(self):
81 return self.Subtype(len(self.ne))
83 @classmethod
84 def _cost(cls, subtype):
85 return subtype.argdim + 2
87 def _expression_names(self):
88 yield "ne"
89 yield "ub1"
90 yield "ub2"
92 def _str(self):
93 a = glyphs.le(glyphs.squared(glyphs.norm(self.ne.string)),
94 glyphs.clever_mul(self.ub1.string, self.ub2.string))
96 if self.ub1.is1:
97 b = glyphs.ge(self.ub2.string, 0)
98 elif self.ub2.is1:
99 b = glyphs.ge(self.ub1.string, 0)
100 else:
101 b = glyphs.ge(glyphs.comma(self.ub1.string, self.ub2.string), 0)
103 return glyphs.and_(a, b)
105 def _get_size(self):
106 return (len(self.ne) + 2, 1)
108 def _get_slack(self):
109 return self.ub1.safe_value * self.ub2.safe_value \
110 - (abs(self.ne)**2).safe_value
113# --------------------------------------
114__all__ = api_end(_API_START, globals())