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

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# ------------------------------------------------------------------------------ 

18 

19"""Rotated second order cone constraints.""" 

20 

21from collections import namedtuple 

22 

23from .. import glyphs 

24from ..apidoc import api_end, api_start 

25from ..caching import cached_property 

26from .constraint import ConicConstraint 

27 

28_API_START = api_start(globals()) 

29# ------------------------------- 

30 

31 

32class RSOCConstraint(ConicConstraint): 

33 """Rotated second order cone membership constraint.""" 

34 

35 def __init__(self, normedExpression, upperBoundFactor1, 

36 upperBoundFactor2=None, customString=None): 

37 """Construct a :class:`RSOCConstraint`. 

38 

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 

51 

52 if upperBoundFactor2 is None: 

53 upperBoundFactor2 = AffineExpression.from_constant(1) 

54 

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 

60 

61 self.ne = normedExpression 

62 self.ub1 = upperBoundFactor1 

63 self.ub2 = upperBoundFactor2 

64 

65 super(RSOCConstraint, self).__init__( 

66 self._get_type_term(), customString, printSize=True) 

67 

68 def _get_type_term(self): 

69 return "RSOC" 

70 

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)) 

77 

78 Subtype = namedtuple("Subtype", ("argdim",)) 

79 

80 def _subtype(self): 

81 return self.Subtype(len(self.ne)) 

82 

83 @classmethod 

84 def _cost(cls, subtype): 

85 return subtype.argdim + 2 

86 

87 def _expression_names(self): 

88 yield "ne" 

89 yield "ub1" 

90 yield "ub2" 

91 

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)) 

95 

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) 

102 

103 return glyphs.and_(a, b) 

104 

105 def _get_size(self): 

106 return (len(self.ne) + 2, 1) 

107 

108 def _get_slack(self): 

109 return self.ub1.safe_value * self.ub2.safe_value \ 

110 - (abs(self.ne)**2).safe_value 

111 

112 

113# -------------------------------------- 

114__all__ = api_end(_API_START, globals())