Coverage for picos/expressions/set.py: 76.19%
84 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) 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
8# terms of the GNU General Public License as published by the Free Software
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"""Backend for mathematical set type implementations."""
22from abc import ABC, abstractmethod
24from .. import glyphs
25from ..apidoc import api_end, api_start
26from ..caching import cached_property
27from .expression import (ExpressionType, convert_operands, refine_operands,
28 validate_prediction)
30_API_START = api_start(globals())
31# -------------------------------
34class SetType(ExpressionType):
35 """:class:`~picos.expressions.ExpressionType` for sets."""
37 pass
40class Set(ABC):
41 """Abstract base class for mathematical set expressions."""
43 def __init__(self, typeStr, symbStr):
44 """Perform basic initialization for :class:`Set` instances.
46 :param str typeStr: Short string denoting the set type.
47 :param str symbStr: Algebraic string description of the set.
48 """
49 self._typeStr = typeStr
50 self._symbStr = symbStr
52 @property
53 def string(self):
54 """Symbolic string representation of the set."""
55 return self._symbStr
57 @property
58 @abstractmethod
59 def Subtype(self):
60 """Analog to :meth:`.expression.Expression.Subtype`."""
61 pass
63 @property
64 def type(self):
65 """Analog to :meth:`.expression.Expression.type`."""
66 return ExpressionType(self.__class__, self._get_subtype())
68 @classmethod
69 def make_type(cls, *args, **kwargs):
70 """Analog to :meth:`.expression.Expression.make_type`."""
71 return ExpressionType(cls, cls.Subtype(*args, **kwargs))
73 @property
74 def subtype(self):
75 """Analog to :meth:`.expression.Expression.subtype`."""
76 return self._get_subtype()
78 @property
79 def refined(self):
80 """The set itself, as sets do not support refinement.
82 This exists for compatibility with expressions.
83 """
84 return self
86 def __repr__(self):
87 return str(glyphs.repr2(self._typeStr, self._symbStr))
89 def __str__(self):
90 return str(self._symbStr)
92 def __format__(self, format_spec):
93 return self._symbStr.__format__(format_spec)
95 @abstractmethod
96 def _get_subtype(self):
97 """:meth:`picos.expressions.Expression._get_subtype`."""
98 pass
100 @classmethod
101 @abstractmethod
102 def _predict(cls, subtype, relation, other):
103 """See :meth:`picos.expressions.Expression._predict`."""
104 pass
106 @abstractmethod
107 def _get_mutables(self):
108 """Return a Python set of mutables that are involved in the set."""
109 pass
111 mutables = property(
112 lambda self: self._get_mutables(),
113 doc=_get_mutables.__doc__)
115 @cached_property
116 def variables(self):
117 """The set of decision variables that are involved in the set."""
118 from .variables import BaseVariable
120 return frozenset(mutable for mutable in self._get_mutables()
121 if isinstance(mutable, BaseVariable))
123 @cached_property
124 def parameters(self):
125 """The set of parameters that are involved in the set."""
126 from .variables import BaseVariable
128 return frozenset(mutable for mutable in self._get_mutables()
129 if not isinstance(mutable, BaseVariable))
131 @abstractmethod
132 def _replace_mutables(self, mapping):
133 """See :meth:`~.expression.Expression._replace_mutables`."""
134 pass
136 # HACK: Borrow Expression.replace_mutables.
137 # TODO: Common base class ExpressionOrSet.
138 def replace_mutables(self, new_mutables):
139 """See :meth:`~.expression.Expression.replace_mutables`."""
140 from .expression import Expression
141 return Expression.replace_mutables(self, new_mutables)
143 # --------------------------------------------------------------------------
144 # Turn __lshift__ and __rshift__ into a single binary relation.
145 # This is used for both Loewner order (defining LMIs) and set membership.
146 # TODO: Define this in a common base class of Expression and Set.
147 # --------------------------------------------------------------------------
149 def _lshift_implementation(self, other):
150 return NotImplemented
152 def _rshift_implementation(self, other):
153 return NotImplemented
155 @convert_operands()
156 @validate_prediction
157 @refine_operands()
158 def __lshift__(self, other):
159 result = self._lshift_implementation(other)
161 if result is NotImplemented:
162 result = other._rshift_implementation(self)
164 return result
166 @convert_operands()
167 @validate_prediction
168 @refine_operands()
169 def __rshift__(self, other):
170 result = self._rshift_implementation(other)
172 if result is NotImplemented:
173 result = other._lshift_implementation(self)
175 return result
178# --------------------------------------
179__all__ = api_end(_API_START, globals())