From c3682ad600c3e7f24033a87a626bbd12f8ae1153 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 7 Jul 2021 22:44:52 +0200 Subject: [PATCH 1/4] initialize backend ppl from ppl_polyhedron --- src/sage/geometry/polyhedron/backend_ppl.py | 51 ++++++++++++++++++--- src/sage/geometry/polyhedron/base.py | 30 ++++++------ src/sage/geometry/polyhedron/parent.py | 27 ++++++++++- 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 52d0f04a851..0075aef484c 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -2,6 +2,7 @@ The PPL (Parma Polyhedra Library) backend for polyhedral computations """ +from sage.structure.element import Element from sage.rings.all import ZZ from sage.rings.integer import Integer from sage.arith.functions import LCM_list @@ -34,6 +35,32 @@ class Polyhedron_ppl(Polyhedron_base): sage: TestSuite(p).run() """ + def __init__(self, parent, Vrep, Hrep, ppl_polyhedron=None, **kwds): + """ + Initializes the polyhedron. + + See :class:`Polyhedron_normaliz` for a description of the input + data. + + TESTS:: + + sage: p = Polyhedron() + sage: TestSuite(p).run() + sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)]) + sage: TestSuite(p).run() + sage: q = polytopes.cube() + sage: p = q.parent().element_class(q.parent(), None, None, q._ppl_polyhedron) + sage: TestSuite(p).run() + """ + if ppl_polyhedron: + if Hrep is not None or Vrep is not None: + raise ValueError("only one of Vrep, Hrep, or ppl_polyhedron can be different from None") + Element.__init__(self, parent=parent) + minimize = True if 'minimize' in kwds and kwds['minimize'] else False + self._init_from_ppl_polyhedron(ppl_polyhedron, minimize) + else: + Polyhedron_base.__init__(self, parent, Vrep, Hrep, **kwds) + def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False): """ Construct polyhedron from V-representation data. @@ -87,11 +114,10 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo dl = [ d*l_i for l_i in l ] gs.insert(line(Linear_Expression(dl, 0))) if gs.empty(): - self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') + ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') else: - self._ppl_polyhedron = C_Polyhedron(gs) - self._init_Vrepresentation_from_ppl(minimize) - self._init_Hrepresentation_from_ppl(minimize) + ppl_polyhedron = C_Polyhedron(gs) + self._init_from_ppl_polyhedron(ppl_polyhedron, minimize) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ @@ -132,9 +158,22 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): A = deqn[1:] cs.insert(Linear_Expression(A, b) == 0) if cs.empty(): - self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') + ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') else: - self._ppl_polyhedron = C_Polyhedron(cs) + ppl_polyhedron = C_Polyhedron(cs) + self._init_from_ppl_polyhedron(ppl_polyhedron, minimize) + + def _init_from_ppl_polyhedron(self, ppl_polyhedron, minimize=True): + """ + Create the V-/Hrepresentation objects from the ppl polyhedron. + + TESTS:: + + sage: p = Polyhedron(backend='ppl') + sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl + sage: Polyhedron_ppl._init_from_Hrepresentation(p, [], []) # indirect doctest + """ + self._ppl_polyhedron = ppl_polyhedron self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index cf2e2f24ada..45e28afc373 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -6044,29 +6044,29 @@ def wedge(self, face, width=1): sage: W2 = Q.wedge(Q.faces(2)[7]); W2 A 4-dimensional polyhedron in QQ^5 defined as the convex hull of 9 vertices sage: W2.vertices() - (A vertex at (0, 1, 0, 1, 0), - A vertex at (0, 0, 1, 1, 0), - A vertex at (1, 0, 0, 1, -1), - A vertex at (1, 0, 0, 1, 1), - A vertex at (1, 0, 1, 0, 1), + (A vertex at (1, 1, 0, 0, 1), A vertex at (1, 1, 0, 0, -1), - A vertex at (0, 1, 1, 0, 0), + A vertex at (1, 0, 1, 0, 1), A vertex at (1, 0, 1, 0, -1), - A vertex at (1, 1, 0, 0, 1)) + A vertex at (1, 0, 0, 1, 1), + A vertex at (1, 0, 0, 1, -1), + A vertex at (0, 0, 1, 1, 0), + A vertex at (0, 1, 1, 0, 0), + A vertex at (0, 1, 0, 1, 0)) sage: W3 = Q.wedge(Q.faces(1)[11]); W3 A 4-dimensional polyhedron in QQ^5 defined as the convex hull of 10 vertices sage: W3.vertices() - (A vertex at (0, 1, 0, 1, 0), - A vertex at (0, 0, 1, 1, 0), - A vertex at (1, 0, 0, 1, -1), - A vertex at (1, 0, 0, 1, 1), + (A vertex at (1, 1, 0, 0, -2), + A vertex at (1, 1, 0, 0, 2), + A vertex at (1, 0, 1, 0, -2), A vertex at (1, 0, 1, 0, 2), + A vertex at (1, 0, 0, 1, 1), + A vertex at (1, 0, 0, 1, -1), + A vertex at (0, 1, 0, 1, 0), A vertex at (0, 1, 1, 0, 1), - A vertex at (1, 0, 1, 0, -2), - A vertex at (1, 1, 0, 0, 2), - A vertex at (0, 1, 1, 0, -1), - A vertex at (1, 1, 0, 0, -2)) + A vertex at (0, 0, 1, 1, 0), + A vertex at (0, 1, 1, 0, -1)) sage: C_3_7 = polytopes.cyclic_polytope(3,7) sage: P_6 = polytopes.regular_polygon(6) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 57f3a349bfc..8b365d8d487 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -614,7 +614,7 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: P = Polyhedra(QQ, 3) + sage: P = Polyhedra(QQ, 3, backend='cdd') sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) sage: p A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices @@ -1081,6 +1081,31 @@ class Polyhedra_ZZ_normaliz(Polyhedra_base): class Polyhedra_QQ_ppl(Polyhedra_base): Element = Polyhedron_QQ_ppl + def _element_constructor_polyhedron(self, polyhedron, **kwds): + """ + The element (polyhedron) constructor for the case of 1 argument, a polyhedron. + + Set up with the ``ppl_polyhedron`` of ``self``, if available. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: P = Polyhedra(QQ, 3) + sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) + sage: p + A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + sage: P(p) + A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices + + sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)], backend='cdd') + sage: P(p) + A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices + """ + if polyhedron.backend() == "ppl": + return self._element_constructor_(None, None, ppl_polyhedron=polyhedron._ppl_polyhedron) + else: + return Polyhedra_base._element_constructor_polyhedron(self, polyhedron, **kwds) + class Polyhedra_QQ_normaliz(Polyhedra_base): Element = Polyhedron_QQ_normaliz From 5e81afa9584314b5fa9ed84ee54fcffa43a386c3 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 7 Jul 2021 23:06:52 +0200 Subject: [PATCH 2/4] outsource ppl conversion --- src/sage/geometry/polyhedron/backend_ppl.py | 99 +++++++++++++++------ 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 0075aef484c..1bf5f0b7484 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -91,28 +91,13 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo gs = Generator_System() if vertices is None: vertices = [] for v in vertices: - d = LCM_list([denominator(v_i) for v_i in v]) - if d.is_one(): - gs.insert(point(Linear_Expression(v, 0))) - else: - dv = [ d*v_i for v_i in v ] - gs.insert(point(Linear_Expression(dv, 0), d)) + gs.insert(self._convert_generator_to_ppl(v, 2)) if rays is None: rays = [] for r in rays: - d = LCM_list([denominator(r_i) for r_i in r]) - if d.is_one(): - gs.insert(ray(Linear_Expression(r, 0))) - else: - dr = [ d*r_i for r_i in r ] - gs.insert(ray(Linear_Expression(dr, 0))) + gs.insert(self._convert_generator_to_ppl(r, 3)) if lines is None: lines = [] for l in lines: - d = LCM_list([denominator(l_i) for l_i in l]) - if d.is_one(): - gs.insert(line(Linear_Expression(l, 0))) - else: - dl = [ d*l_i for l_i in l ] - gs.insert(line(Linear_Expression(dl, 0))) + gs.insert(self._convert_generator_to_ppl(l, 4)) if gs.empty(): ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') else: @@ -145,18 +130,10 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): cs = Constraint_System() if ieqs is None: ieqs = [] for ieq in ieqs: - d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) - dieq = [ ZZ(d*ieq_i) for ieq_i in ieq ] - b = dieq[0] - A = dieq[1:] - cs.insert(Linear_Expression(A, b) >= 0) + cs.insert(self._convert_constraint_to_ppl(ieq, 0)) if eqns is None: eqns = [] for eqn in eqns: - d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) - deqn = [ ZZ(d*eqn_i) for eqn_i in eqn ] - b = deqn[0] - A = deqn[1:] - cs.insert(Linear_Expression(A, b) == 0) + cs.insert(self._convert_constraint_to_ppl(eqn, 1)) if cs.empty(): ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') else: @@ -263,6 +240,72 @@ def _init_empty_polyhedron(self): super(Polyhedron_ppl, self)._init_empty_polyhedron() self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') + @staticmethod + def _convert_generator_to_ppl(v, typ): + r""" + Convert a generator to ``ppl``. + + INPUT: + + - ``v`` -- a vertex, ray, or line. + + - ``typ`` -- integer; 2 -- vertex; 3 -- ray; 4 -- line + + EXAMPLES:: + + sage: P = Polyhedron() + sage: P._convert_generator_to_ppl([1, 1/2, 3], 2) + point(2/2, 1/2, 6/2) + sage: P._convert_generator_to_ppl([1, 1/2, 3], 3) + ray(2, 1, 6) + sage: P._convert_generator_to_ppl([1, 1/2, 3], 4) + line(2, 1, 6) + """ + if typ == 2: + ob = point + elif typ == 3: + ob = ray + else: + ob = line + + d = LCM_list([denominator(v_i) for v_i in v]) + if d.is_one(): + return ob(Linear_Expression(v, 0)) + else: + dv = [ d*v_i for v_i in v ] + if typ == 2: + return ob(Linear_Expression(dv, 0), d) + else: + return ob(Linear_Expression(dv, 0)) + + @staticmethod + def _convert_constraint_to_ppl(c, typ): + r""" + Convert a constraint to ``ppl``. + + INPUT: + + - ``c`` -- an inequality or equation. + + - ``typ`` -- integer; 0 -- inequality; 3 -- equation + + EXAMPLES:: + + sage: P = Polyhedron() + sage: P._convert_constraint_to_ppl([1, 1/2, 3], 0) + x0+6*x1+2>=0 + sage: P._convert_constraint_to_ppl([1, 1/2, 3], 1) + x0+6*x1+2==0 + """ + d = LCM_list([denominator(c_i) for c_i in c]) + dc = [ ZZ(d*c_i) for c_i in c ] + b = dc[0] + A = dc[1:] + if typ == 0: + return Linear_Expression(A, b) >= 0 + else: + return Linear_Expression(A, b) == 0 + From 51248442053ebf1ead7ef97d6276f030795a7026 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 8 Jul 2021 14:38:32 +0200 Subject: [PATCH 3/4] add _element_constructore_polyhedron for ppl over ZZ --- src/sage/geometry/polyhedron/parent.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 8b365d8d487..f2be3b68d09 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -1075,6 +1075,31 @@ def _make_Line(self, polyhedron, data): class Polyhedra_ZZ_ppl(Polyhedra_base): Element = Polyhedron_ZZ_ppl + def _element_constructor_polyhedron(self, polyhedron, **kwds): + """ + The element (polyhedron) constructor for the case of 1 argument, a polyhedron. + + Set up with the ``ppl_polyhedron`` of ``self``, if available. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: P = Polyhedra(ZZ, 3) + sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)], base_ring=QQ) + sage: p + A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices + sage: P(p) + A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + + sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)], backend='cdd') + sage: P(p) + A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + """ + if polyhedron.backend() == "ppl": + return self._element_constructor_(None, None, ppl_polyhedron=polyhedron._ppl_polyhedron) + else: + return Polyhedra_base._element_constructor_polyhedron(self, polyhedron, **kwds) + class Polyhedra_ZZ_normaliz(Polyhedra_base): Element = Polyhedron_ZZ_normaliz From c82c14410cb123c79cf5107865864298c1be94d0 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 8 Jul 2021 17:01:20 +0200 Subject: [PATCH 4/4] remove copy paste typo --- src/sage/geometry/polyhedron/backend_ppl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 1bf5f0b7484..f23a728b995 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -39,7 +39,7 @@ def __init__(self, parent, Vrep, Hrep, ppl_polyhedron=None, **kwds): """ Initializes the polyhedron. - See :class:`Polyhedron_normaliz` for a description of the input + See :class:`Polyhedron_ppl` for a description of the input data. TESTS::