Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
allow ppl polyhedron to be mutable
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Kliem committed Jul 13, 2021
1 parent d4f6fb7 commit 1ece615
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 33 deletions.
57 changes: 47 additions & 10 deletions src/sage/geometry/polyhedron/backend_ppl.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Polyhedron_ppl(Polyhedron_mutable):

_backend_object_name = "ppl_polyhedron"

def __init__(self, parent, Vrep, Hrep, ppl_polyhedron=None, **kwds):
def __init__(self, parent, Vrep, Hrep, ppl_polyhedron=None, mutable=False, **kwds):
"""
Initializes the polyhedron.
Expand All @@ -62,6 +62,9 @@ def __init__(self, parent, Vrep, Hrep, ppl_polyhedron=None, **kwds):
self._init_from_ppl_polyhedron(ppl_polyhedron, minimize)
else:
Polyhedron_mutable.__init__(self, parent, Vrep, Hrep, **kwds)
self._is_mutable = True
if not mutable:
self.set_immutable()

def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False):
"""
Expand Down Expand Up @@ -154,6 +157,27 @@ def _init_from_ppl_polyhedron(self, ppl_polyhedron, minimize=True):
"""
self._ppl_polyhedron = ppl_polyhedron

def set_immutable(self):
r"""
Make this polyhedron immutable. This operation cannot be undone.
EXAMPLES::
sage: p = Polyhedron([[1, 1]], mutable=True)
sage: p.is_mutable()
True
sage: hasattr(p, "_Vrepresentation")
False
sage: p.set_immutable()
sage: hasattr(p, "_Vrepresentation")
True
"""
if not hasattr(self, '_Vrepresentation'):
self._init_Vrepresentation_from_ppl(True)
if not hasattr(self, '_Hrepresentation'):
self._init_Hrepresentation_from_ppl(True)
self._is_mutable = False

def Vrepresentation(self, index=None):
"""
Return the objects of the V-representation. Each entry is
Expand All @@ -179,16 +203,16 @@ def Vrepresentation(self, index=None):
sage: p = polytopes.cube()
sage: p.Vrepresentation(0)
A vertex at (1, -1, -1)
::
sage: P = p.parent()
sage: p = P._element_constructor_(p, mutable=True)
sage: p.Vrepresentation(0)
A vertex at (1, -1, -1)
sage: p._clear_cache()
sage: p.Vrepresentation()
(A vertex at (1, -1, -1),
A vertex at (1, 1, -1),
A vertex at (1, 1, 1),
A vertex at (1, -1, 1),
A vertex at (-1, -1, 1),
A vertex at (-1, -1, -1),
A vertex at (-1, 1, -1),
A vertex at (-1, 1, 1))
sage: p.Vrepresentation(0)
A vertex at (1, -1, -1)
sage: TestSuite(p).run()
"""
if not hasattr(self, '_Vrepresentation'):
Expand Down Expand Up @@ -217,6 +241,8 @@ def _init_Vrepresentation_from_ppl(self, minimize):
sage: p._ppl_polyhedron.minimized_generators()
Generator_System {point(0/2, 1/2), point(2/1, 0/1), point(24/6, 5/6)}
"""
if not self._is_mutable:
raise TypeError("Vrepresentation of mutable polyhedra cannot be recomputed")
self._Vrepresentation = []
gs = self._ppl_polyhedron.minimized_generators()
parent = self.parent()
Expand Down Expand Up @@ -255,6 +281,8 @@ def _init_Hrepresentation_from_ppl(self, minimize):
sage: p._ppl_polyhedron.minimized_generators()
Generator_System {point(0/2, 1/2), point(2/1, 0/1), point(24/6, 5/6)}
"""
if not self._is_mutable:
raise TypeError("Hrepresentation of mutable polyhedra cannot be recomputed")
self._Hrepresentation = []
cs = self._ppl_polyhedron.minimized_constraints()
parent = self.parent()
Expand Down Expand Up @@ -289,7 +317,16 @@ def Hrepresentation(self, index=None):
An inequality (-1, 0, 0) x + 1 >= 0
sage: p.Hrepresentation(0) == p.Hrepresentation()[0]
True
::
sage: P = p.parent()
sage: p = P._element_constructor_(p, mutable=True)
sage: p.Hrepresentation(0)
An inequality (-1, 0, 0) x + 1 >= 0
sage: p._clear_cache()
sage: p.Hrepresentation(0)
An inequality (-1, 0, 0) x + 1 >= 0
sage: TestSuite(p).run()
"""
if not hasattr(self, '_Hrepresentation'):
Expand Down
12 changes: 10 additions & 2 deletions src/sage/geometry/polyhedron/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class Polyhedron_base(Element, ConvexSet_closed):
one of``Vrep`` or ``Hrep`` to pick this in case the backend
cannot initialize from complete double description
- ``mutable`` -- ignored
If both ``Vrep`` and ``Hrep`` are provided, then
``Vrep_minimal`` and ``Hrep_minimal`` must be set to ``True``.
Expand Down Expand Up @@ -171,7 +173,7 @@ class Polyhedron_base(Element, ConvexSet_closed):
sage: TestSuite(P).run()
"""

def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, **kwds):
def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds):
"""
Initializes the polyhedron.
Expand Down Expand Up @@ -607,7 +609,7 @@ def base_extend(self, base_ring, backend=None):
"""
new_parent = self.parent().base_extend(base_ring, backend)
return new_parent(self)
return new_parent(self, copy=True)

def change_ring(self, base_ring, backend=None):
"""
Expand Down Expand Up @@ -778,6 +780,12 @@ def _is_subpolyhedron(self, other):
for other_H in other.Hrepresentation()
for self_V in self.Vrepresentation())

def is_mutable(self):
return False

def is_immutable(self):
return True

@cached_method
def vertex_facet_graph(self, labels=True):
r"""
Expand Down
88 changes: 84 additions & 4 deletions src/sage/geometry/polyhedron/base_mutable.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,102 @@


class Polyhedron_mutable(Polyhedron_base):
"""
Base class for polyhedra that allow mutability.
This should not be used directly.
"""

def __hash__(self):
r"""
TESTS::
sage: p = Polyhedron([[1, 1]], mutable=True)
sage: set([p])
Traceback (most recent call last):
...
TypeError: mutable polyhedra are unhashable
sage: p.set_immutable()
sage: set([p])
{A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex}
"""
if self._is_mutable:
raise TypeError("mutable polyhedra are unhashable")
return Polyhedron_base.__hash__(self)

def _clear_cache(self):
r"""
Clear the Vrepresentation and Hrepresentation data of ``self``.
TESTS::
sage: P = polytopes.permutahedron(4)
sage: TestSuite(P).run()
sage: P._clear_cache()
sage: TestSuite(P).run()
sage: p = polytopes.permutahedron(4)
sage: P = p.parent()
sage: q = P._element_constructor_(p, mutable=True)
sage: TestSuite(q).run()
sage: q._clear_cache()
sage: TestSuite(q).run()
::
sage: q.set_immutable()
sage: q._clear_cache()
Traceback (most recent call last):
...
TypeError: cannot clear cache of immutable polyhedra
"""
if not self._is_mutable:
raise TypeError("cannot clear cache of immutable polyhedra")
self.parent().recycle(self)
backend_object = self.__dict__["_" + self._backend_object_name]
del self.__dict__
self.__dict__["_" + self._backend_object_name] = backend_object
self._is_mutable = True

def is_mutable(self):
r"""
Return True if the polyhedron is mutable, i.e. it can be modified in place.
EXAMPLES::
sage: p = Polyhedron([[1, 1]], mutable=True)
sage: p.is_mutable()
True
sage: p = Polyhedron([[1, 1]], mutable=False)
sage: p.is_mutable()
False
"""
return self._is_mutable

def is_immutable(self):
r"""
Return True if the polyhedron is immutable, i.e. it cannot be modified in place.
EXAMPLES::
sage: p = Polyhedron([[1, 1]], mutable=True)
sage: p.is_immutable()
False
sage: p = Polyhedron([[1, 1]], mutable=False)
sage: p.is_immutable()
True
"""
return not self._is_mutable

def set_immutable(self):
r"""
Make this polyhedron immutable. This operation cannot be undone.
TESTS::
sage: from sage.geometry.polyhedron.base_mutable import Polyhedron_mutable
sage: p = polytopes.cube()
sage: Polyhedron_mutable.set_immutable(p)
Traceback (most recent call last):
...
NotImplementedError: a derived class must implement this
"""
raise NotImplementedError("a derived class must implement this")

def Vrepresentation(self):
r"""
Expand Down
38 changes: 26 additions & 12 deletions src/sage/geometry/polyhedron/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@
def Polyhedron(vertices=None, rays=None, lines=None,
ieqs=None, eqns=None,
ambient_dim=None, base_ring=None, minimize=True, verbose=False,
backend=None):
backend=None, mutable=False):
r"""
Construct a polyhedron object.
Expand Down Expand Up @@ -346,32 +346,35 @@ def Polyhedron(vertices=None, rays=None, lines=None,
* ``'cdd'``: use cdd
(:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
`\RDF` coefficients depending on ``base_ring``.
`\RDF` coefficients depending on ``base_ring``
* ``'normaliz'``: use normaliz
(:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or
`\QQ` coefficients depending on ``base_ring``.
`\QQ` coefficients depending on ``base_ring``
* ``'polymake'``: use polymake
(:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or
``QuadraticField`` coefficients depending on ``base_ring``.
``QuadraticField`` coefficients depending on ``base_ring``
* ``'ppl'``: use ppl
(:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
`\QQ` coefficients depending on ``base_ring``.
`\QQ` coefficients depending on ``base_ring``
* ``'field'``: use python implementation
(:mod:`~sage.geometry.polyhedron.backend_field`) for any field
Some backends support further optional arguments:
- ``minimize`` -- boolean (default: ``True``). Whether to
immediately remove redundant H/V-representation data. Currently
- ``minimize`` -- boolean (default: ``True``); whether to
immediately remove redundant H/V-representation data; currently
not used.
- ``verbose`` -- boolean (default: ``False``). Whether to print
verbose output for debugging purposes. Only supported by the cdd and
normaliz backends.
- ``verbose`` -- boolean (default: ``False``); whether to print
verbose output for debugging purposes; only supported by the cdd and
normaliz backends
- ``mutable`` -- boolean (default: ``False``); whether the polyhedron
is mutable
OUTPUT:
Expand Down Expand Up @@ -460,6 +463,18 @@ def Polyhedron(vertices=None, rays=None, lines=None,
...
ValueError: invalid base ring
Create a mutable polyhedron::
sage: P = Polyhedron(vertices=[[0, 1], [1, 0]], mutable=True)
sage: P.is_mutable()
True
sage: hasattr(P, "_Vrepresentation")
False
sage: P.Vrepresentation()
(A vertex at (0, 1), A vertex at (1, 0))
sage: hasattr(P, "_Vrepresentation")
True
.. NOTE::
* Once constructed, a ``Polyhedron`` object is immutable.
Expand Down Expand Up @@ -505,7 +520,6 @@ def Polyhedron(vertices=None, rays=None, lines=None,
....: (2, 3, 1), (3, 1, 2), (3, 2, 1)],
....: rays=[[1, 1, 1]], lines=[[1, 2, 3]], backend='ppl',
....: base_ring=ZZ)
sage: Q.n_vertices()
Traceback (most recent call last):
...
TypeError: no conversion of this rational to integer
Expand Down Expand Up @@ -659,4 +673,4 @@ def Polyhedron(vertices=None, rays=None, lines=None,
Hrep = [ieqs, eqns]
if got_Vrep:
Vrep = [vertices, rays, lines]
return parent(Vrep, Hrep, convert=convert, verbose=verbose)
return parent(Vrep, Hrep, convert=convert, verbose=verbose, mutable=mutable)
10 changes: 9 additions & 1 deletion src/sage/geometry/polyhedron/face.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,16 @@ def __hash__(self):
2377136578164722109,
5966674064902575359,
4795242501625591634]
The face of a mutable polyhedron is immutable::
sage: p = Polyhedron([[1, 1]], mutable=True)
sage: f = p.faces(0)[0]
sage: _ = hash(f)
"""
return hash((self._polyhedron, self._ambient_Vrepresentation_indices))
from .base import Polyhedron_base
# The face of an mutable polyhedron is still mutable and is invalid when the polyhedron is changed.
return hash((Polyhedron_base.__hash__(self._polyhedron), self._ambient_Vrepresentation_indices))

def vertex_generator(self):
"""
Expand Down
Loading

0 comments on commit 1ece615

Please sign in to comment.