Coverage for picos/expressions/cone_nno.py: 97.83%
46 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-15 14:21 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-15 14:21 +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 the nonnegative orthant cone."""
21import operator
22from collections import namedtuple
24from .. import glyphs
25from ..apidoc import api_end, api_start
26from ..constraints import AffineConstraint
27from ..constraints.uncertain import ConicallyUncertainAffineConstraint
28from .cone import Cone
29from .exp_affine import AffineExpression
30from .uncertain.pert_conic import ConicPerturbationSet
31from .uncertain.uexp_affine import UncertainAffineExpression
33_API_START = api_start(globals())
34# -------------------------------
37class NonnegativeOrthant(Cone):
38 """The nonnegative orthant."""
40 def __init__(self, dim=None):
41 """Construct a :class:`NonnegativeOrthant`."""
42 Cone.__init__(self, dim, "Nonnegative Orthant",
43 glyphs.set(glyphs.ge("x", glyphs.scalar(0))))
45 def _get_mutables(self):
46 return frozenset()
48 def _replace_mutables(self):
49 return self
51 Subtype = namedtuple("Subtype", ("dim",))
53 def _get_subtype(self):
54 return self.Subtype(self.dim)
56 @classmethod
57 def _predict(cls, subtype, relation, other):
58 assert isinstance(subtype, cls.Subtype)
60 if relation == operator.__rshift__:
61 if issubclass(other.clstype, AffineExpression) \
62 and not subtype.dim or subtype.dim == other.subtype.dim:
63 return AffineConstraint.make_type(
64 dim=other.subtype.dim, eq=False)
65 elif issubclass(other.clstype, UncertainAffineExpression) \
66 and not subtype.dim or subtype.dim == other.subtype.dim:
67 universe = other.subtype.universe_type
69 if issubclass(universe.clstype, ConicPerturbationSet):
70 return ConicallyUncertainAffineConstraint.make_type(
71 dim=other.subtype.dim,
72 universe_subtype=universe.subtype)
74 return Cone._predict_base(cls, subtype, relation, other)
76 def _rshift_implementation(self, element):
77 if isinstance(element, AffineExpression):
78 self._check_dimension(element)
80 return element >= 0
81 elif isinstance(element, UncertainAffineExpression):
82 self._check_dimension(element)
84 if isinstance(element.universe, ConicPerturbationSet):
85 return ConicallyUncertainAffineConstraint(-element)
87 # Handle scenario uncertainty for all cones.
88 return Cone._rshift_base(self, element)
90 @property
91 def dual_cone(self):
92 """Implement :attr:`.cone.Cone.dual_cone`."""
93 return self
96# --------------------------------------
97__all__ = api_end(_API_START, globals())