Skip to content

Commit

Permalink
Trac #27993: Make outer normal fans readily available
Browse files Browse the repository at this point in the history
For a polytope `P`, both `NormalFan(P)` and `P.normal_fan()` return the
inner normal fan having the inner facet normals as rays. The outer
normal fan, using the outer facet normals, is well-known, but not as
easy to find in Sage.

As an example, create the polytope on p.193 of Ziegler's "Lectures on
Polytopes" with its normal fan:
{{{
sage: V=[(-8,-4),(-8,6),(-4,-8),(0,-9),(0,6),(4,-8)]
sage: P=Polyhedron(V)
sage: NormalFan(P)
}}}

The result is the inner normal fan of `P`, which is the outer normal fan
of `-P`.

This ticket adds to `Polyhedron.normal_fan` an argument `direction` set
to either `'inner'` or `'outer'` to determine which of the directions to
use. The default will stay `'inner'` in order to match the default of
`NormalFan`. The description of `NormalFan` is extended by a hint to use
`NormalFan(-P)` for the outer normal fan.

Additionally, this ticket adds in
`sage.geometry.polyhedron.representation` a method
`Inequality.outer_normal`.
This allows to obtain the outer normal vector without having to think
about the appropriate sign of `Inequality.A()` whenever dealing with the
facet inequalities of a polyhedron.

URL: https://trac.sagemath.org/27993
Reported by: nailuj
Ticket author(s): Julian Ritter
Reviewer(s): Jean-Philippe Labbé, Frédéric Chapoton
  • Loading branch information
Release Manager committed Jul 29, 2019
2 parents 9e9a2a4 + 440689c commit d9e5056
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/sage/geometry/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,9 @@ def NormalFan(polytope, lattice=None):
r"""
Construct the normal fan of the given rational ``polytope``.
This returns the inner normal fan. For the outer normal fan, use
``NormalFan(-P)``.
INPUT:
- ``polytope`` -- a full-dimensional :func:`polytope
Expand Down
44 changes: 40 additions & 4 deletions src/sage/geometry/polyhedron/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,6 @@ def change_ring(self, base_ring, backend=None):
"""

from sage.categories.all import Rings
from sage.rings.all import RDF, RR

if base_ring not in Rings:
raise ValueError("invalid base ring")
Expand Down Expand Up @@ -2753,10 +2752,19 @@ def gale_transform(self):
return A_ker.basis_matrix().transpose().rows()

@cached_method
def normal_fan(self):
def normal_fan(self, direction='inner'):
r"""
Return the normal fan of a compact full-dimensional rational polyhedron.
This returns the inner normal fan of ``self``. For the outer normal fan,
use ``direction='outer'``.
INPUT:
- ``direction`` -- either ``'inner'`` (default) or ``'outer'``; if
set to ``'inner'``, use the inner normal vectors to span the cones of
the fan, if set to ``'outer'``, use the outer normal vectors.
OUTPUT:
A complete fan of the ambient space as a
Expand Down Expand Up @@ -2796,6 +2804,30 @@ def normal_fan(self):
...
NotImplementedError: normal fan handles only polytopes over the rationals
sage: P = Polyhedron(vertices=[[0,0],[2,0],[0,2],[2,1],[1,2]])
sage: P.normal_fan(direction=None)
Traceback (most recent call last):
...
TypeError: the direction should be 'inner' or 'outer'
sage: inner_nf = P.normal_fan()
sage: inner_nf.rays()
N( 1, 0),
N( 0, -1),
N( 0, 1),
N(-1, 0),
N(-1, -1)
in 2-d lattice N
sage: outer_nf = P.normal_fan(direction='outer')
sage: outer_nf.rays()
N( 1, 0),
N( 1, 1),
N( 0, 1),
N(-1, 0),
N( 0, -1)
in 2-d lattice N
REFERENCES:
For more information, see Chapter 7 of [Zie2007]_.
Expand All @@ -2804,8 +2836,12 @@ def normal_fan(self):

if not QQ.has_coerce_map_from(self.base_ring()):
raise NotImplementedError('normal fan handles only polytopes over the rationals')

return NormalFan(self)
if direction == 'inner':
return NormalFan(self)
elif direction == 'outer':
return NormalFan(-self)
else:
raise TypeError("the direction should be 'inner' or 'outer'")

@cached_method
def face_fan(self):
Expand Down
17 changes: 17 additions & 0 deletions src/sage/geometry/polyhedron/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,23 @@ def interior_contains(self, Vobj):
else: # Vobj.is_ray()
return self.polyhedron()._is_nonneg( self.eval(Vobj) )

def outer_normal(self):
r"""
Return the outer normal vector of ``self``.
OUTPUT:
The normal vector directed away from the interior of the polyhedron.
EXAMPLES::
sage: p = Polyhedron(vertices = [[0,0,0],[1,1,0],[1,2,0]])
sage: a = next(p.inequality_generator())
sage: a.outer_normal()
(1, -1, 0)
"""
return -self.A()


class Equation(Hrepresentation):
"""
Expand Down

0 comments on commit d9e5056

Please sign in to comment.