diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index a2010e67e33..9c4192205cf 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1658,9 +1658,12 @@ REFERENCES: constrained optimization. ACM Transactions on Mathematical Software, Vol 23, Num. 4, pp.550--560, 1997. -.. [Zie1998] G. Ziegler. *Shelling polyhedral 3-balls and +.. [Zie1998] G. M. Ziegler. *Shelling polyhedral 3-balls and 4-polytopes*. Discrete Comput. Geom. 19 (1998), 159-174. +.. [Zie2007] G. M. Ziegler. *Lectures on polytopes*, Volume + 152 of Graduate Texts in Mathematics, 7th printing of 1st edition, Springer, 2007. + .. [Zor2008] \A. Zorich "Explicit Jenkins-Strebel representatives of all strata of Abelian and quadratic differentials", Journal of Modern Dynamics, vol. 2, no 1, 139-185 (2008) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 50d99f99e46..cb85668b3a4 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -464,7 +464,7 @@ def _is_subpolyhedron(self, other): for self_V in self.Vrepresentation()) def plot(self, - point=None, line=None, polygon=None, # None means unspecified by the user + point=None, line=None, polygon=None, # None means unspecified by the user wireframe='blue', fill='green', projection_direction=None, **kwds): @@ -1554,9 +1554,9 @@ def vertices_matrix(self, base_ring=None): if base_ring is None: base_ring = self.base_ring() m = matrix(base_ring, self.ambient_dim(), self.n_vertices()) - for i,v in enumerate(self.vertices()): + for i, v in enumerate(self.vertices()): for j in range(self.ambient_dim()): - m[j,i] = v[j] + m[j, i] = v[j] return m def ray_generator(self): @@ -2390,6 +2390,114 @@ def gale_transform(self): A_ker = A.right_kernel() return A_ker.basis_matrix().transpose().rows() + @cached_method + def normal_fan(self): + r""" + Return the normal fan of a compact full-dimensional rational polyhedron. + + OUTPUT: + + A complete fan of the ambient space as a + :class:`~sage.geometry.fan.RationalPolyhedralFan`. + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.base.face_fan`. + + EXAMPLES:: + + sage: S = Polyhedron(vertices = [[0, 0], [1, 0], [0, 1]]) + sage: S.normal_fan() + Rational polyhedral fan in 2-d lattice N + + sage: C = polytopes.hypercube(4) + sage: NF = C.normal_fan(); NF + Rational polyhedral fan in 4-d lattice N + + Currently, it is only possible to get the normal fan of a bounded rational polytope:: + + sage: P = Polyhedron(rays = [[1, 0], [0, 1]]) + sage: P.normal_fan() + Traceback (most recent call last): + ... + NotImplementedError: the normal fan is only supported for polytopes (compact polyhedra). + + sage: Q = Polyhedron(vertices = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + sage: Q.normal_fan() + Traceback (most recent call last): + ... + ValueError: the normal fan is only defined for full-dimensional polytopes + + sage: R = Polyhedron(vertices = [[0, 0], [AA(sqrt(2)), 0], [0, AA(sqrt(2))]]) + sage: R.normal_fan() + Traceback (most recent call last): + ... + NotImplementedError: normal fan handles only polytopes over the rationals + + REFERENCES: + + For more information, see Chapter 7 of [Zie2007]_. + """ + from sage.geometry.fan import NormalFan + + if not QQ.has_coerce_map_from(self.base_ring()): + raise NotImplementedError('normal fan handles only polytopes over the rationals') + + return NormalFan(self) + + @cached_method + def face_fan(self): + r""" + Return the face fan of a compact rational polyhedron. + + OUTPUT: + + A fan of the ambient space as a + :class:`~sage.geometry.fan.RationalPolyhedralFan`. + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.base.normal_fan`. + + EXAMPLES:: + + sage: T = polytopes.cuboctahedron() + sage: T.face_fan() + Rational polyhedral fan in 3-d lattice M + + The polytope should contain the origin in the interior:: + + sage: P = Polyhedron(vertices = [[1/2, 1], [1, 1/2]]) + sage: P.face_fan() + Traceback (most recent call last): + ... + ValueError: face fans are defined only for polytopes containing the origin as an interior point! + + sage: Q = Polyhedron(vertices = [[-1, 1/2], [1, -1/2]]) + sage: Q.contains([0,0]) + True + sage: FF = Q.face_fan(); FF + Rational polyhedral fan in 2-d lattice M + + The polytope has to have rational coordinates:: + + sage: S = polytopes.dodecahedron() + sage: S.face_fan() + Traceback (most recent call last): + ... + NotImplementedError: face fan handles only polytopes over the rationals + + REFERENCES: + + For more information, see Chapter 7 of [Zie2007]_. + """ + from sage.geometry.fan import FaceFan + + if not QQ.has_coerce_map_from(self.base_ring()): + raise NotImplementedError('face fan handles only polytopes over the rationals') + + return FaceFan(self) + def triangulate(self, engine='auto', connected=True, fine=False, regular=None, star=None): r""" Returns a triangulation of the polytope.