Path: blob/master/src/sage/geometry/polyhedron/constructor.py
8817 views
r"""1Polyhedra23In this module, a polyhedron is a convex (possibly unbounded) set in4Euclidean space cut out by a finite set of linear inequalities and5linear equations. Note that the dimension of the polyhedron can be6less than the dimension of the ambient space. There are two7complementary representations of the same data:89**H(alf-space/Hyperplane)-representation**10This describes a polyhedron as the common solution set of a11finite number of1213* linear **inequalities** `A \vec{x} + b \geq 0`, and1415* linear **equations** `C \vec{x} + d = 0`.161718**V(ertex)-representation**19The other representation is as the convex hull of vertices (and20rays and lines to all for unbounded polyhedra) as generators. The21polyhedron is then the Minkowski sum2223.. MATH::2425P = \text{conv}\{v_1,\dots,v_k\} +26\sum_{i=1}^m \RR_+ r_i +27\sum_{j=1}^n \RR \ell_j2829where3031* **vertices** `v_1`, `\dots`, `v_k` are a finite number of32points. Each vertex is specified by an arbitrary vector, and two33points are equal if and only if the vector is the same.3435* **rays** `r_1`, `\dots`, `r_m` are a finite number of directions36(directions of infinity). Each ray is specified by a non-zero37vector, and two rays are equal if and only if the vectors are38the same up to rescaling with a positive constant.3940* **lines** `\ell_1`, `\dots`, `\ell_n` are a finite number of41unoriented directions. In other words, a line is equivalent to42the set `\{r, -r\}` for a ray `r`. Each line is specified by a43non-zero vector, and two lines are equivalent if and only if the44vectors are the same up to rescaling with a non-zero (possibly45negative) constant.4647When specifying a polyhedron, you can input a non-minimal set of48inequalities/equations or generating vertices/rays/lines. The49non-minimal generators are usually called points, non-extremal rays,50and non-extremal lines, but for our purposes it is more convenient to51always talk about vertices/rays/lines. Sage will remove any52superfluous representation objects and always return a minimal53representation. For example, `(0,0)` is a superfluous vertex here::5455sage: triangle = Polyhedron(vertices=[(0,2), (-1,0), (1,0), (0,0)])56sage: triangle.vertices()57(A vertex at (-1, 0), A vertex at (1, 0), A vertex at (0, 2))5859A polytope is defined as a bounded polyhedron. In this case, the60minimal representation is unique and a vertex of the minimal61representation is equivalent to a 0-dimensional face of the62polytope. This is why one generally does not distinguish vertices and630-dimensional faces. But for non-bounded polyhedra we have to allow64for a more general notion of "vertex" in order to make sense of the65Minkowsi sum presentation::6667sage: half_plane = Polyhedron(ieqs=[(0,1,0)])68sage: half_plane.Hrepresentation()69(An inequality (1, 0) x + 0 >= 0,)70sage: half_plane.Vrepresentation()71(A line in the direction (0, 1), A ray in the direction (1, 0), A vertex at (0, 0))7273Note how we need a point in the above example to anchor the ray and74line. But any point on the boundary of the half-plane would serve the75purpose just as well. Sage picked the origin here, but this choice is76not unique. Similarly, the choice of ray is arbitrary but necessary to77generate the half-plane.7879Finally, note that while rays and lines generate unbounded edges of80the polyhedron they are not in a one-to-one correspondence with81them. For example, the infinite strip has two infinite edges (1-faces)82but only one generating line::8384sage: strip = Polyhedron(vertices=[(1,0),(-1,0)], lines=[(0,1)])85sage: strip.Hrepresentation()86(An inequality (1, 0) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0)87sage: strip.lines()88(A line in the direction (0, 1),)89sage: strip.faces(1)90(<0,1>, <0,2>)91sage: for face in strip.faces(1):92... print face, '=', face.as_polyhedron().Vrepresentation()93<0,1> = (A line in the direction (0, 1), A vertex at (-1, 0))94<0,2> = (A line in the direction (0, 1), A vertex at (1, 0))9596EXAMPLES::9798sage: trunc_quadr = Polyhedron(vertices=[[1,0],[0,1]], rays=[[1,0],[0,1]])99sage: trunc_quadr100A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 2 rays101sage: v = trunc_quadr.vertex_generator().next() # the first vertex in the internal enumeration102sage: v103A vertex at (0, 1)104sage: v.vector()105(0, 1)106sage: list(v)107[0, 1]108sage: len(v)1092110sage: v[0] + v[1]1111112sage: v.is_vertex()113True114sage: type(v)115<class 'sage.geometry.polyhedron.representation.Vertex'>116sage: type( v() )117<type 'sage.modules.vector_integer_dense.Vector_integer_dense'>118sage: v.polyhedron()119A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 2 rays120sage: r = trunc_quadr.ray_generator().next()121sage: r122A ray in the direction (0, 1)123sage: r.vector()124(0, 1)125sage: list( v.neighbors() )126[A ray in the direction (0, 1), A vertex at (1, 0)]127128Inequalities `A \vec{x} + b \geq 0` (and, similarly, equations) are129specified by a list ``[b, A]``::130131sage: Polyhedron(ieqs=[(0,1,0),(0,0,1),(1,-1,-1)]).Hrepresentation()132(An inequality (-1, -1) x + 1 >= 0,133An inequality (1, 0) x + 0 >= 0,134An inequality (0, 1) x + 0 >= 0)135136See :func:`Polyhedron` for a detailed description of all possible ways137to construct a polyhedron.138139REFERENCES:140141Komei Fukuda's `FAQ in Polyhedral Computation142<http://www.ifor.math.ethz.ch/~fukuda/polyfaq/polyfaq.html>`_143144AUTHORS:145146- Marshall Hampton: first version, bug fixes, and various improvements, 2008 and 2009147- Arnaud Bergeron: improvements to triangulation and rendering, 2008148- Sebastien Barthelemy: documentation improvements, 2008149- Volker Braun: refactoring, handle non-compact case, 2009 and 2010150- Andrey Novoseltsev: added Hasse_diagram_from_incidences, 2010151- Volker Braun: rewrite to use PPL instead of cddlib, 2011152"""153154########################################################################155# Copyright (C) 2008 Marshall Hampton <[email protected]>156# Copyright (C) 2011 Volker Braun <[email protected]>157#158# Distributed under the terms of the GNU General Public License (GPL)159#160# http://www.gnu.org/licenses/161########################################################################162163from sage.rings.all import QQ, ZZ, RDF164from sage.misc.decorators import rename_keyword165166from misc import _make_listlist, _common_length_of167168169170171172173#########################################################################174@rename_keyword(deprecation=11634, field='base_ring')175def Polyhedron(vertices=None, rays=None, lines=None,176ieqs=None, eqns=None,177ambient_dim=None, base_ring=None, minimize=True, verbose=False,178backend=None):179"""180Construct a polyhedron object.181182You may either define it with vertex/ray/line or183inequalities/equations data, but not both. Redundant data will184automatically be removed (unless ``minimize=False``), and the185complementary representation will be computed.186187INPUT:188189- ``vertices`` -- list of point. Each point can be specified as190any iterable container of ``base_ring`` elements. If ``rays`` or191``lines`` are specified but no ``vertices``, the origin is192taken to be the single vertex.193194- ``rays`` -- list of rays. Each ray can be specified as any195iterable container of ``base_ring`` elements.196197- ``lines`` -- list of lines. Each line can be specified as any198iterable container of ``base_ring`` elements.199200- ``ieqs`` -- list of inequalities. Each line can be specified as any201iterable container of ``base_ring`` elements. An entry equal to202``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.203204- ``eqns`` -- list of equalities. Each line can be specified as205any iterable container of ``base_ring`` elements. An entry equal to206``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.207208- ``base_ring`` -- either ``QQ`` or ``RDF``. The field over which209the polyhedron will be defined. For ``QQ``, exact arithmetic210will be used. For ``RDF``, floating point numbers will be211used. Floating point arithmetic is faster but might give the212wrong result for degenerate input.213214- ``ambient_dim`` -- integer. The ambient space dimension. Usually215can be figured out automatically from the H/Vrepresentation216dimensions.217218- ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are219220* ``'cdd'``: use cdd221(:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or222`\RDF` coefficients depending on ``base_ring``.223224225* ``'ppl'``: use ppl226(:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or227`\QQ` coefficients depending on ``base_ring``.228229Some backends support further optional arguments:230231- ``minimize`` -- boolean (default: ``True``). Whether to232immediately remove redundant H/V-representation data. Currently233not used.234235- ``verbose`` -- boolean (default: ``False``). Whether to print236verbose output for debugging purposes. Only supported by the cdd237backends.238239OUTPUT:240241The polyhedron defined by the input data.242243EXAMPLES:244245Construct some polyhedra::246247sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])248sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])249sage: list(square_from_ieqs.vertex_generator())250[A vertex at (1, -1),251A vertex at (1, 1),252A vertex at (-1, 1),253A vertex at (-1, -1)]254sage: list(square_from_vertices.inequality_generator())255[An inequality (1, 0) x + 1 >= 0,256An inequality (0, 1) x + 1 >= 0,257An inequality (-1, 0) x + 1 >= 0,258An inequality (0, -1) x + 1 >= 0]259sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)260sage: p.n_inequalities()2612262263The same polyhedron given in two ways::264265sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])266sage: p.Vrepresentation()267(A line in the direction (0, 0, 1),268A ray in the direction (1, 0, 0),269A ray in the direction (0, 1, 0),270A vertex at (0, 0, 0))271sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])272sage: q.Hrepresentation()273(An inequality (1, 0, 0) x + 0 >= 0,274An inequality (0, 1, 0) x + 0 >= 0)275276Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with277coordinates `a, b, \dots, f` and278279* The inequality `e+b \geq c+d`280* The inequality `e+c \geq b+d`281* The equation `a+b+c+d+e+f = 31`282283::284285sage: positive_coords = Polyhedron(ieqs=[286... [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],287... [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])288sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (289... [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])290sage: P291A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices292sage: P.dim()2935294sage: P.Vrepresentation()295(A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),296A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),297A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),298A vertex at (0, 0, 0, 31/2, 31/2, 0))299300.. NOTE::301302* Once constructed, a ``Polyhedron`` object is immutable.303* Although the option ``field=RDF`` allows numerical data to304be used, it might not give the right answer for degenerate305input data - the results can depend upon the tolerance306setting of cdd.307"""308# Clean up the arguments309vertices = _make_listlist(vertices)310rays = _make_listlist(rays)311lines = _make_listlist(lines)312ieqs = _make_listlist(ieqs)313eqns = _make_listlist(eqns)314315got_Vrep = (len(vertices+rays+lines) > 0)316got_Hrep = (len(ieqs+eqns) > 0)317318if got_Vrep and got_Hrep:319raise ValueError('You cannot specify both H- and V-representation.')320elif got_Vrep:321deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]322elif got_Hrep:323deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1324else:325if ambient_dim is None:326deduced_ambient_dim = 0327else:328deduced_ambient_dim = ambient_dim329if base_ring is None:330base_ring = ZZ331332# set ambient_dim333if ambient_dim is not None and deduced_ambient_dim!=ambient_dim:334raise ValueError('Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.')335ambient_dim = deduced_ambient_dim336337# figure out base_ring338from sage.misc.flatten import flatten339values = flatten(vertices+rays+lines+ieqs+eqns)340if base_ring is not None:341try:342convert = not all(x.parent() is base_ring for x in values)343except AttributeError: # No x.parent() method?344convert = True345else:346from sage.rings.integer import is_Integer347from sage.rings.rational import is_Rational348from sage.rings.real_double import is_RealDoubleElement349if all(is_Integer(x) for x in values):350if got_Vrep:351base_ring = ZZ352else: # integral inequalities usually do not determine a latice polytope!353base_ring = QQ354convert=False355elif all(is_Rational(x) for x in values):356base_ring = QQ357convert=False358elif all(is_RealDoubleElement(x) for x in values):359base_ring = RDF360convert=False361else:362try:363map(ZZ, values)364if got_Vrep:365base_ring = ZZ366else:367base_ring = QQ368convert = True369except TypeError:370from sage.structure.sequence import Sequence371values = Sequence(values)372if QQ.has_coerce_map_from(values.universe()):373base_ring = QQ374convert = True375else:376base_ring = RDF377convert = True378379# Add the origin if necesarry380if got_Vrep and len(vertices)==0:381vertices = [ [0]*ambient_dim ]382383# Specific backends can override the base_ring384from sage.geometry.polyhedron.parent import Polyhedra385parent = Polyhedra(base_ring, ambient_dim, backend=backend)386base_ring = parent.base_ring()387388# Convert into base_ring if necessary389def convert_base_ring(lstlst):390return [ [base_ring(x) for x in lst] for lst in lstlst]391Hrep = Vrep = None392if got_Hrep:393Hrep = [ieqs, eqns]394if got_Vrep:395Vrep = [vertices, rays, lines]396397# finally, construct the Polyhedron398return parent(Vrep, Hrep, convert=convert, verbose=verbose)399400401