Coverage for picos/expressions/cone_trivial.py: 74.60%

63 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-26 07:46 +0000

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

2# Copyright (C) 2020 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"""Implements trivial cones.""" 

20 

21import operator 

22from collections import namedtuple 

23 

24from .. import glyphs 

25from ..apidoc import api_end, api_start 

26from ..caching import cached_property 

27from ..constraints import (AffineConstraint, ComplexAffineConstraint, 

28 DummyConstraint) 

29from .cone import Cone 

30from .exp_affine import AffineExpression, ComplexAffineExpression 

31 

32_API_START = api_start(globals()) 

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

34 

35 

36class ZeroSpace(Cone): 

37 r"""The set containing zero.""" 

38 

39 def __init__(self, dim=None): 

40 """Construct a :class:`ZeroSpace`.""" 

41 Cone.__init__(self, dim, "Zero Space", glyphs.set(glyphs.scalar(0))) 

42 

43 def _get_mutables(self): 

44 return frozenset() 

45 

46 def _replace_mutables(self): 

47 return self 

48 

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

50 

51 def _get_subtype(self): 

52 return self.Subtype(self.dim) 

53 

54 @classmethod 

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

56 assert isinstance(subtype, cls.Subtype) 

57 

58 if relation == operator.__rshift__: 

59 if issubclass(other.clstype, AffineExpression) \ 

60 and not subtype.dim or subtype.dim == other.subtype.dim: 

61 return AffineConstraint.make_type( 

62 dim=other.subtype.dim, eq=True) 

63 elif issubclass(other.clstype, ComplexAffineExpression) \ 

64 and not subtype.dim or subtype.dim == other.subtype.dim: 

65 return ComplexAffineConstraint.make_type( 

66 dim=other.subtype.dim) 

67 

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

69 

70 def _rshift_implementation(self, element): 

71 if isinstance(element, ComplexAffineExpression): 

72 self._check_dimension(element) 

73 

74 return element == 0 

75 

76 # Handle scenario uncertainty for all cones. 

77 return Cone._rshift_base(self, element) 

78 

79 @cached_property 

80 def dual_cone(self): 

81 """Implement :attr:`.cone.Cone.dual_cone`.""" 

82 return TheField(dim=self.dim) 

83 

84 

85class TheField(Cone): 

86 r"""The real or complex field.""" 

87 

88 def __init__(self, dim=None): 

89 """Construct a :class:`TheField`.""" 

90 Cone.__init__(self, dim, "The Field", "F") 

91 

92 def _get_mutables(self): 

93 return frozenset() 

94 

95 def _replace_mutables(self): 

96 return self 

97 

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

99 

100 def _get_subtype(self): 

101 return self.Subtype(self.dim) 

102 

103 @classmethod 

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

105 assert isinstance(subtype, cls.Subtype) 

106 

107 if relation == operator.__rshift__: 

108 if issubclass(other.clstype, ComplexAffineExpression) \ 

109 and not subtype.dim or subtype.dim == other.subtype.dim: 

110 return DummyConstraint.make_type() 

111 

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

113 

114 def _rshift_implementation(self, element): 

115 if isinstance(element, ComplexAffineExpression): 

116 self._check_dimension(element) 

117 

118 return DummyConstraint(element) 

119 

120 # Handle scenario uncertainty for all cones. 

121 return Cone._rshift_base(self, element) 

122 

123 @cached_property 

124 def dual_cone(self): 

125 """Implement :attr:`.cone.Cone.dual_cone`.""" 

126 return ZeroSpace(dim=self.dim) 

127 

128 

129# -------------------------------------- 

130__all__ = api_end(_API_START, globals())