r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# ------------------------------------------------------------------------------

2# Copyright (C) 2019 Maximilian Stahlberg

3# Based on the original picos.expressions module by Guillaume Sagnol.

4#

5# This file is part of PICOS.

6#

7# PICOS is free software: you can redistribute it and/or modify it under the

9# Foundation, either version 3 of the License, or (at your option) any later

10# version.

11#

12# PICOS is distributed in the hope that it will be useful, but WITHOUT ANY

13# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR

14# A PARTICULAR PURPOSE. See the GNU General Public License for more details.

15#

16# You should have received a copy of the GNU General Public License along with

17# this program. If not, see <http://www.gnu.org/licenses/>.

18# ------------------------------------------------------------------------------

20"""Implements :class:RotatedSecondOrderCone."""

22import operator

23from collections import namedtuple

25from .. import glyphs

26from ..apidoc import api_end, api_start

27from ..caching import cached_property

28from ..constraints import RSOCConstraint

29from .cone import Cone

30from .exp_affine import AffineExpression

32_API_START = api_start(globals())

33# -------------------------------

36class RotatedSecondOrderCone(Cone):

37 r"""The (narrowed or widened) rotated second order cone.

39 .. _rotatedcone:

41 For :math:n \in \mathbb{Z}_{\geq 3} and :math:p \in \mathbb{R}_{> 0},

42 represents the convex cone

44 .. math::

46 \mathcal{R}_{p}^n = \left\{

47 x \in \mathbb{R}^n

48 ~\middle|~

49 p x_1 x_2 \geq \sum_{i = 3}^n x_i^2 \land x_1, x_2 \geq 0

50 \right\}.

52 For :math:p = 2, this is the standard rotated second order cone

53 :math:\mathcal{R}^n obtained by rotating the

54 :class:second order cone <picos.SecondOrderCone> :math:\mathcal{Q}^n

55 by :math:\frac{\pi}{4} in the :math:(x_1, x_2) plane.

57 The default instance of this class has :math:p = 1, which can be

58 understood as a narrowed version of the standard cone. This is more

59 convenient for defining the primal problem but it should be noted that

60 :math:\mathcal{R}_{1}^n is not self-dual, so working with

61 :math:p = 2 may seem more natural when the dual problem is of interest.

63 :Dual cone:

65 The dual cone is

67 .. math::

69 \left(\mathcal{R}_{p}^n\right)^* = \left\{

70 x \in \mathbb{R}^n

71 ~\middle|~

72 \frac{4}{p} x_1 x_2 \geq \sum_{i = 2}^n x_i^2 \land x_1, x_2 \geq 0

73 \right\}=\mathcal{R}_{4/p}^n.

75 The cone is thus self-dual for :math:p = 2.

76 """

78 def __init__(self, p=1, dim=None):

79 """Construct a rotated second order cone.

81 :param float p:

82 The positive factor :math:p in the definition.

83 """

84 try:

85 p = float(p)

86 except Exception as error:

87 raise TypeError("Failed to load the parameter 'p' as a float.") \

88 from error

90 if p <= 0:

91 raise ValueError("The parameter 'p' must be positive.")

93 self._p = p

95 if dim and dim < 3:

96 raise ValueError("The minimal dimension for {} is {}."

97 .format(self.__class__.__name__, 3))

99 typeStr = "Rotated Second Order Cone"

100 if p < 2:

101 typeStr = "Narrowed " + typeStr

102 elif p > 2:

103 typeStr = "Widened " + typeStr

105 symbStr = glyphs.set(glyphs.sep(

106 glyphs.col_vectorize("u", "v", "x"), glyphs.and_(

107 glyphs.le(

108 glyphs.squared(glyphs.norm("x")),

109 glyphs.clever_mul(glyphs.scalar(p), glyphs.mul("u", "v"))),

110 glyphs.ge("u", 0))))

112 Cone.__init__(self, dim, typeStr, symbStr)

114 @property

115 def p(self):

116 """A narrowing (:math:p < 2) or widening (:math:p > 2) factor."""

117 return self._p

119 def _get_mutables(self):

120 return frozenset()

122 def _replace_mutables(self):

123 return self

125 Subtype = namedtuple("Subtype", ("dim",))

127 def _get_subtype(self):

128 return self.Subtype(self.dim)

130 @classmethod

131 def _predict(cls, subtype, relation, other):

132 assert isinstance(subtype, cls.Subtype)

134 if relation == operator.__rshift__:

135 if issubclass(other.clstype, AffineExpression) \

136 and not subtype.dim or subtype.dim == other.subtype.dim \

137 and other.subtype.dim >= 3:

138 return RSOCConstraint.make_type(other.subtype.dim - 2)

140 return Cone._predict_base(cls, subtype, relation, other)

142 def _rshift_implementation(self, element):

143 if isinstance(element, AffineExpression):

144 self._check_dimension(element)

146 if len(element) < 3:

147 raise TypeError("Elements of the rotated second order cone must"

148 " be at least three-dimensional.")

150 element = element.vec

152 return RSOCConstraint(element[2:], self.p * element[0], element[1])

154 # Handle scenario uncertainty for all cones.

155 return Cone._rshift_base(self, element)

157 @cached_property

158 def dual_cone(self):

159 """Implement :attr:.cone.Cone.dual_cone."""

160 return self.__class__(p=(4.0/self._p), dim=self.dim)

163# --------------------------------------

164__all__ = api_end(_API_START, globals())