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
« 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# ------------------------------------------------------------------------------
19"""Implements trivial cones."""
21import operator
22from collections import namedtuple
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
32_API_START = api_start(globals())
33# -------------------------------
36class ZeroSpace(Cone):
37 r"""The set containing zero."""
39 def __init__(self, dim=None):
40 """Construct a :class:`ZeroSpace`."""
41 Cone.__init__(self, dim, "Zero Space", glyphs.set(glyphs.scalar(0)))
43 def _get_mutables(self):
44 return frozenset()
46 def _replace_mutables(self):
47 return self
49 Subtype = namedtuple("Subtype", ("dim",))
51 def _get_subtype(self):
52 return self.Subtype(self.dim)
54 @classmethod
55 def _predict(cls, subtype, relation, other):
56 assert isinstance(subtype, cls.Subtype)
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)
68 return Cone._predict_base(cls, subtype, relation, other)
70 def _rshift_implementation(self, element):
71 if isinstance(element, ComplexAffineExpression):
72 self._check_dimension(element)
74 return element == 0
76 # Handle scenario uncertainty for all cones.
77 return Cone._rshift_base(self, element)
79 @cached_property
80 def dual_cone(self):
81 """Implement :attr:`.cone.Cone.dual_cone`."""
82 return TheField(dim=self.dim)
85class TheField(Cone):
86 r"""The real or complex field."""
88 def __init__(self, dim=None):
89 """Construct a :class:`TheField`."""
90 Cone.__init__(self, dim, "The Field", "F")
92 def _get_mutables(self):
93 return frozenset()
95 def _replace_mutables(self):
96 return self
98 Subtype = namedtuple("Subtype", ("dim",))
100 def _get_subtype(self):
101 return self.Subtype(self.dim)
103 @classmethod
104 def _predict(cls, subtype, relation, other):
105 assert isinstance(subtype, cls.Subtype)
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()
112 return Cone._predict_base(cls, subtype, relation, other)
114 def _rshift_implementation(self, element):
115 if isinstance(element, ComplexAffineExpression):
116 self._check_dimension(element)
118 return DummyConstraint(element)
120 # Handle scenario uncertainty for all cones.
121 return Cone._rshift_base(self, element)
123 @cached_property
124 def dual_cone(self):
125 """Implement :attr:`.cone.Cone.dual_cone`."""
126 return ZeroSpace(dim=self.dim)
129# --------------------------------------
130__all__ = api_end(_API_START, globals())