Skip to content

Commit

Permalink
Trac #29198: Set up hypercube with both Vrep and Hrep (if backend sup…
Browse files Browse the repository at this point in the history
…ports it)

Currently, the hypercube is set up with the vertices. This is slow, as
the vertices grow exponentially with dimension:

{{{
sage: %time _ = polytopes.hypercube(8)
CPU times: user 58.6 ms, sys: 0 ns, total: 58.6 ms
Wall time: 58.2 ms
sage: %time _ = polytopes.hypercube(14)
CPU times: user 2.74 s, sys: 19.1 ms, total: 2.76 s
Wall time: 2.76 s
}}}

With #28880 at hand, we can set up the hypercube with both Vrep and
Hrep. If the backend supports it (as in `backend='field'`), then the
double description does not need to be computed. If the backend does not
support it (as in `backend='ppl'`), then the hypercube is set up from
the inequalities, which is much faster:

{{{
sage: %time _ = polytopes.hypercube(8)   # uses ppl
CPU times: user 47.8 ms, sys: 3.19 ms, total: 51 ms
Wall time: 50 ms
sage: %time _ = polytopes.hypercube(14)  # uses ppl
CPU times: user 421 ms, sys: 4.7 ms, total: 426 ms
Wall time: 425 ms
sage: %time _ = polytopes.hypercube(14, backend='field')  # uses both
descriptions
CPU times: user 168 ms, sys: 124 µs, total: 169 ms
Wall time: 168 ms
}}}

URL: https://trac.sagemath.org/29198
Reported by: gh-kliem
Ticket author(s): Jonathan Kliem
Reviewer(s): Jean-Philippe Labbé, Sébastien Labbé
  • Loading branch information
Release Manager committed Mar 7, 2020
2 parents 1c7ea20 + 91ae9ba commit b9dd82b
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 172 deletions.
12 changes: 6 additions & 6 deletions src/sage/geometry/integral_points.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -507,19 +507,19 @@ cpdef rectangular_box_points(list box_min, list box_max,
sage: cube = polytopes.cube()
sage: cube.Hrepresentation(0)
An inequality (0, 0, -1) x + 1 >= 0
An inequality (-1, 0, 0) x + 1 >= 0
sage: cube.Hrepresentation(1)
An inequality (0, -1, 0) x + 1 >= 0
sage: cube.Hrepresentation(2)
An inequality (-1, 0, 0) x + 1 >= 0
An inequality (0, 0, -1) x + 1 >= 0
sage: rectangular_box_points([0]*3, [1]*3, cube, return_saturated=True)
(((0, 0, 0), frozenset()),
((0, 0, 1), frozenset({0})),
((0, 0, 1), frozenset({2})),
((0, 1, 0), frozenset({1})),
((0, 1, 1), frozenset({0, 1})),
((1, 0, 0), frozenset({2})),
((0, 1, 1), frozenset({1, 2})),
((1, 0, 0), frozenset({0})),
((1, 0, 1), frozenset({0, 2})),
((1, 1, 0), frozenset({1, 2})),
((1, 1, 0), frozenset({0, 1})),
((1, 1, 1), frozenset({0, 1, 2})))
TESTS:
Expand Down
98 changes: 52 additions & 46 deletions src/sage/geometry/polyhedron/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ def Hrepresentation(self, index=None):
sage: p = polytopes.hypercube(3)
sage: p.Hrepresentation(0)
An inequality (0, 0, -1) x + 1 >= 0
An inequality (-1, 0, 0) x + 1 >= 0
sage: p.Hrepresentation(0) == p.Hrepresentation() [0]
True
"""
Expand Down Expand Up @@ -1522,7 +1522,7 @@ def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=Non
sage: c = polytopes.cube()
sage: c.Hrepresentation_str(separator=', ', style='positive')
'1 >= x2, 1 >= x1, 1 >= x0, x0 + 1 >= 0, x2 + 1 >= 0, x1 + 1 >= 0'
'1 >= x0, 1 >= x1, 1 >= x2, x0 + 1 >= 0, x2 + 1 >= 0, x1 + 1 >= 0'
"""
pretty_hs = [h.repr_pretty(split=True, latex=latex, style=style, **kwds) for h in self.Hrepresentation()]
shift = any(pretty_h[2].startswith('-') for pretty_h in pretty_hs)
Expand Down Expand Up @@ -1574,7 +1574,7 @@ def Hrep_generator(self):
sage: p = polytopes.hypercube(3)
sage: next(p.Hrep_generator())
An inequality (0, 0, -1) x + 1 >= 0
An inequality (-1, 0, 0) x + 1 >= 0
"""
for H in self.Hrepresentation():
yield H
Expand Down Expand Up @@ -1993,8 +1993,8 @@ def an_affine_basis(self):
sage: P.an_affine_basis()
[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 = polytopes.permutahedron(5)
sage: P.an_affine_basis()
Expand Down Expand Up @@ -2804,7 +2804,7 @@ def a_maximal_chain(self):
A 2-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 4 vertices,
A 3-dimensional face of a Polyhedron in ZZ^3 defined as the convex hull of 8 vertices]
sage: [face.ambient_V_indices() for face in chain]
[(), (0,), (0, 4), (0, 1, 4, 5), (0, 1, 2, 3, 4, 5, 6, 7)]
[(), (5,), (0, 5), (0, 3, 4, 5), (0, 1, 2, 3, 4, 5, 6, 7)]
TESTS::
Expand Down Expand Up @@ -3333,14 +3333,14 @@ def is_prism(self, certificate=False):
True
sage: P.is_prism(certificate=True)
(True,
[[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),
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: Q = polytopes.cyclic_polytope(3,8)
sage: Q.is_prism()
False
Expand Down Expand Up @@ -3740,13 +3740,15 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s
sage: triangulation = cube.triangulate(
....: engine='internal') # to make doctest independent of TOPCOM
sage: triangulation
(<0,1,2,7>, <0,1,4,7>, <0,2,4,7>, <1,2,3,7>, <1,4,5,7>, <2,4,6,7>)
(<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>)
sage: simplex_indices = triangulation[0]; simplex_indices
(0, 1, 2, 7)
sage: simplex_vertices = [ cube.Vrepresentation(i) for i in simplex_indices ]
sage: simplex_vertices
[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: Polyhedron(simplex_vertices)
A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices
Expand Down Expand Up @@ -4860,13 +4862,13 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None):
sage: edge_trunc.f_vector()
(1, 10, 15, 7, 1)
sage: tuple(f.ambient_V_indices() for f in edge_trunc.faces(2))
((0, 4, 5, 6),
(0, 1, 6, 7),
(5, 6, 7, 8, 9),
(3, 4, 5, 9),
(1, 2, 7, 8),
(2, 3, 8, 9),
(0, 1, 2, 3, 4))
((0, 5, 6, 7),
(1, 4, 5, 6, 8),
(6, 7, 8, 9),
(0, 2, 3, 7, 9),
(1, 2, 8, 9),
(0, 3, 4, 5),
(1, 2, 3, 4))
sage: face_trunc = Cube.face_truncation(Cube.faces(2)[2])
sage: face_trunc.vertices()
(A vertex at (1, -1, -1),
Expand Down Expand Up @@ -5840,23 +5842,27 @@ def faces(self, face_dimension):
sage: p = polytopes.hypercube(4)
sage: list(f.ambient_V_indices() for f in p.faces(3))
[(0, 2, 4, 6, 8, 10, 12, 14),
(0, 1, 4, 5, 8, 9, 12, 13),
(0, 1, 2, 3, 8, 9, 10, 11),
(0, 1, 2, 3, 4, 5, 6, 7),
(1, 3, 5, 7, 9, 11, 13, 15),
(2, 3, 6, 7, 10, 11, 14, 15),
(4, 5, 6, 7, 12, 13, 14, 15),
(8, 9, 10, 11, 12, 13, 14, 15)]
[(0, 5, 6, 7, 8, 9, 14, 15),
(1, 4, 5, 6, 10, 13, 14, 15),
(1, 2, 6, 7, 8, 10, 11, 15),
(8, 9, 10, 11, 12, 13, 14, 15),
(0, 3, 4, 5, 9, 12, 13, 14),
(0, 2, 3, 7, 8, 9, 11, 12),
(1, 2, 3, 4, 10, 11, 12, 13),
(0, 1, 2, 3, 4, 5, 6, 7)]
sage: face = p.faces(3)[3]
sage: face.ambient_Hrepresentation()
(An inequality (1, 0, 0, 0) x + 1 >= 0,)
sage: face.vertices()
(A vertex at (-1, -1, -1, -1), A vertex at (-1, -1, -1, 1),
A vertex at (-1, -1, 1, -1), A vertex at (-1, -1, 1, 1),
A vertex at (-1, 1, -1, -1), A vertex at (-1, 1, -1, 1),
A vertex at (-1, 1, 1, -1), A vertex at (-1, 1, 1, 1))
(A vertex at (-1, -1, 1, -1),
A vertex at (-1, -1, 1, 1),
A vertex at (-1, 1, -1, -1),
A vertex at (-1, 1, 1, -1),
A vertex at (-1, 1, 1, 1),
A vertex at (-1, 1, -1, 1),
A vertex at (-1, -1, -1, 1),
A vertex at (-1, -1, -1, -1))
You can use the
:meth:`~sage.geometry.polyhedron.representation.PolyhedronRepresentation.index`
Expand All @@ -5866,19 +5872,19 @@ def faces(self, face_dimension):
sage: [get_idx(_) for _ in face.ambient_Hrepresentation()]
[4]
sage: [get_idx(_) for _ in face.ambient_Vrepresentation()]
[0, 1, 2, 3, 4, 5, 6, 7]
[8, 9, 10, 11, 12, 13, 14, 15]
sage: [ ([get_idx(_) for _ in face.ambient_Vrepresentation()],
....: [get_idx(_) for _ in face.ambient_Hrepresentation()])
....: for face in p.faces(3) ]
[([0, 2, 4, 6, 8, 10, 12, 14], [7]),
([0, 1, 4, 5, 8, 9, 12, 13], [6]),
([0, 1, 2, 3, 8, 9, 10, 11], [5]),
([0, 1, 2, 3, 4, 5, 6, 7], [4]),
([1, 3, 5, 7, 9, 11, 13, 15], [3]),
([2, 3, 6, 7, 10, 11, 14, 15], [2]),
([4, 5, 6, 7, 12, 13, 14, 15], [1]),
([8, 9, 10, 11, 12, 13, 14, 15], [0])]
[([0, 5, 6, 7, 8, 9, 14, 15], [7]),
([1, 4, 5, 6, 10, 13, 14, 15], [6]),
([1, 2, 6, 7, 8, 10, 11, 15], [5]),
([8, 9, 10, 11, 12, 13, 14, 15], [4]),
([0, 3, 4, 5, 9, 12, 13, 14], [3]),
([0, 2, 3, 7, 8, 9, 11, 12], [2]),
([1, 2, 3, 4, 10, 11, 12, 13], [1]),
([0, 1, 2, 3, 4, 5, 6, 7], [0])]
TESTS::
Expand Down Expand Up @@ -6498,7 +6504,7 @@ def one_point_suspension(self, vertex):
It works with a polyhedral face as well::
sage: vv = cube.faces(0)[0]
sage: vv = cube.faces(0)[1]
sage: ops_cube2 = cube.one_point_suspension(vv)
sage: ops_cube == ops_cube2
True
Expand Down Expand Up @@ -6674,7 +6680,7 @@ def schlegel_projection(self, projection_dir=None, height=1.1):
sage: schlegel_edge_indices = sch_proj.lines
sage: schlegel_edges = [sch_proj.coordinates_of(x) for x in schlegel_edge_indices]
sage: len([x for x in schlegel_edges if x[0][0] > 0])
4
5
"""
proj = self.projection()
if projection_dir is None:
Expand Down
72 changes: 36 additions & 36 deletions src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ Construction::
Obtaining edges and ridges::
sage: C.edges()[:2]
((A vertex at (1, 1, 1, -1), A vertex at (1, 1, 1, 1)),
(A vertex at (1, 1, -1, 1), A vertex at (1, 1, 1, 1)))
((A vertex at (-1, -1, -1, 1), A vertex at (-1, -1, -1, -1)),
(A vertex at (-1, 1, -1, -1), A vertex at (-1, -1, -1, -1)))
sage: C.edges(names=False)[:2]
((14, 15), (13, 15))
((14, 15), (10, 15))
sage: C.ridges()[:2]
((An inequality (0, 0, 1, 0) x + 1 >= 0,
An inequality (0, 0, 0, 1) x + 1 >= 0),
(An inequality (0, 1, 0, 0) x + 1 >= 0,
An inequality (0, 0, 0, 1) x + 1 >= 0))
An inequality (0, 1, 0, 0) x + 1 >= 0),
(An inequality (0, 0, 0, 1) x + 1 >= 0,
An inequality (0, 1, 0, 0) x + 1 >= 0))
sage: C.ridges(names=False)[:2]
((6, 7), (5, 7))
Expand Down Expand Up @@ -817,37 +817,37 @@ cdef class CombinatorialPolyhedron(SageObject):
sage: P = polytopes.cube()
sage: C = CombinatorialPolyhedron(P)
sage: C.facets()
((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),
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)),
(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)),
(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)),
(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),
A vertex at (1, -1, 1)))
A vertex at (-1, -1, -1)))
sage: C.facets(names=False)
((1, 3, 5, 7),
(2, 3, 6, 7),
((0, 1, 2, 3),
(1, 2, 6, 7),
(2, 3, 4, 7),
(4, 5, 6, 7),
(0, 1, 2, 3),
(0, 2, 4, 6),
(0, 1, 4, 5))
(0, 1, 5, 6),
(0, 3, 4, 5))
"""
if unlikely(self.dimension() == 0):
# Special attention for this trivial case.
Expand Down Expand Up @@ -889,14 +889,14 @@ cdef class CombinatorialPolyhedron(SageObject):
sage: P = polytopes.cube()
sage: C = P.combinatorial_polyhedron()
sage: C.incidence_matrix()
[1 0 0 0 1 1]
[1 1 0 0 1 0]
[1 1 1 0 0 0]
[1 0 1 0 0 1]
[0 0 1 1 0 1]
[0 0 0 1 1 1]
[1 0 0 1 0 1]
[0 1 0 1 1 0]
[1 1 0 1 0 0]
[0 0 1 0 1 1]
[1 0 1 0 0 1]
[0 1 1 0 1 0]
[1 1 1 0 0 0]
[0 1 1 1 0 0]
sage: P.incidence_matrix() == C.incidence_matrix()
True
Expand Down Expand Up @@ -2010,7 +2010,7 @@ cdef class CombinatorialPolyhedron(SageObject):
A 2-dimensional face of a 4-dimensional combinatorial polyhedron,
A 3-dimensional face of a 4-dimensional combinatorial polyhedron]
sage: [face.ambient_V_indices() for face in chain]
[(0,), (0, 8), (0, 4, 8, 12), (0, 2, 4, 6, 8, 10, 12, 14)]
[(15,), (6, 15), (5, 6, 14, 15), (0, 5, 6, 7, 8, 9, 14, 15)]
sage: P = polytopes.permutahedron(4)
sage: C = P.combinatorial_polyhedron()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,13 @@ cdef class FaceIterator(SageObject):
(1,),
(0,),
(3, 4),
(2, 4),
(1, 4),
(0, 4),
(1, 3, 4),
(1, 2, 4),
(0, 1, 4),
(2, 3),
(1, 3),
(0, 3),
(0, 1, 3),
(1, 2, 3),
(1, 2),
(0, 2),
(0, 1, 2),
Expand Down Expand Up @@ -294,22 +294,22 @@ cdef class FaceIterator(SageObject):
(1,),
(0,),
(6, 7),
(5, 7),
(3, 7),
(4, 7),
(2, 7),
(4, 5, 6, 7),
(2, 3, 6, 7),
(1, 3, 5, 7),
(4, 6),
(2, 6),
(0, 2, 4, 6),
(1, 2, 6, 7),
(2, 3, 4, 7),
(5, 6),
(1, 6),
(0, 1, 5, 6),
(4, 5),
(1, 5),
(0, 1, 4, 5),
(0, 4),
(0, 5),
(0, 3, 4, 5),
(3, 4),
(2, 3),
(1, 3),
(0, 3),
(0, 1, 2, 3),
(0, 2),
(1, 2),
(0, 1)]
sage: it = C.face_iter(dual=False)
Expand Down
Loading

0 comments on commit b9dd82b

Please sign in to comment.