def _pushout_(self, other): r""" The pushout of Polyhedra over ZZ and Associahedra over QQ is Polyhedra over QQ. TESTS:: sage: A = polytopes.associahedron(['A',4], backend='ppl'); type(A.parent()) <class 'sage.combinat.root_system.associahedron.Associahedra_ppl_with_category'> sage: B = polytopes.simplex(); type(B.parent()) <class 'sage.geometry.polyhedron.parent.Polyhedra_ZZ_ppl_with_category'> sage: A + B A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 70 vertices sage: A - B A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 24 vertices sage: A.intersection(B) A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 4 vertices sage: A.convex_hull(B) A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 42 vertices """ if isinstance(other, Polyhedra_base) and other.base_ring() == ZZ: return Polyhedra(QQ, self.ambient_dim(), self.backend()) # Call the overwritten pushout in case it exists. if hasattr(super(Associahedra_base, self), '_pushout_'): return super(Associahedra_base, self)._pushout_(other)
def __init__(self, dim, data_basename=None, output='Polyhedron'): """ The Python constructor See :class:`PALPreader` for documentation. TESTS:: sage: from sage.geometry.polyhedron.palp_database import PALPreader sage: polygons = PALPreader(2) """ self._dim = dim if data_basename is not None: self._data_basename = data_basename else: import os from sage.env import POLYTOPE_DATA_DIR self._data_basename = os.path.join(POLYTOPE_DATA_DIR, 'Full' + str(dim) + 'd', 'zzdb') info = self._data_basename + '.info' if not os.path.exists(info): raise ValueError('Cannot find PALP database: ' + info) from sage.geometry.polyhedron.parent import Polyhedra self._polyhedron_parent = Polyhedra(ZZ, dim) self._output = output.lower()
def __init__(self, points): """ Construct an RNAPolytope from a collection of points. Keyword arguments: points -- An Iterable of points, each of which has (at least) members `structure` (holding arbitrary data about the point) and `vector` (giving the coordinates of the point in a format which can be handled by `Polytope`) """ self._normal_fan = None self._vertex_from_cone = None parent = Polyhedra(QQ, len(points[0].vector)) vertex_list = [point.vector for point in points] super(RNAPolytope, self).__init__(parent, [vertex_list, None, None], None) structure_dict = { tuple(map(QQ, point.vector)): point.structure for point in points } self._structures = structure_dict
def Polyhedron(vertices=None, rays=None, lines=None, ieqs=None, eqns=None, ambient_dim=None, base_ring=None, minimize=True, verbose=False, backend=None): """ Construct a polyhedron object. You may either define it with vertex/ray/line or inequalities/equations data, but not both. Redundant data will automatically be removed (unless ``minimize=False``), and the complementary representation will be computed. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of ``base_ring`` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of ``base_ring`` elements. - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`. - ``base_ring`` -- a sub-field of the reals implemented in Sage. The field over which the polyhedron will be defined. For ``QQ`` and algebraic extensions, exact arithmetic will be used. For ``RDF``, floating point numbers will be used. Floating point arithmetic is faster but might give the wrong result for degenerate input. - ``ambient_dim`` -- integer. The ambient space dimension. Usually can be figured out automatically from the H/Vrepresentation dimensions. - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are * ``'cdd'``: use cdd (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or `\RDF` coefficients depending on ``base_ring``. * ``'ppl'``: use ppl (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring``. * ``'field'``: use python implementation (:mod:`~sage.geometry.polyhedron.backend_field`) for any field Some backends support further optional arguments: - ``minimize`` -- boolean (default: ``True``). Whether to immediately remove redundant H/V-representation data. Currently not used. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. Only supported by the cdd backends. OUTPUT: The polyhedron defined by the input data. EXAMPLES: Construct some polyhedra:: sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]]) sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]]) sage: list(square_from_ieqs.vertex_generator()) [A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, -1)] sage: list(square_from_vertices.inequality_generator()) [An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0] sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF) sage: p.n_inequalities() 2 The same polyhedron given in two ways:: sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]]) sage: p.Vrepresentation() (A line in the direction (0, 0, 1), A ray in the direction (1, 0, 0), A ray in the direction (0, 1, 0), A vertex at (0, 0, 0)) sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]]) sage: q.Hrepresentation() (An inequality (1, 0, 0) x + 0 >= 0, An inequality (0, 1, 0) x + 0 >= 0) Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with coordinates `a, b, \dots, f` and * The inequality `e+b \geq c+d` * The inequality `e+c \geq b+d` * The equation `a+b+c+d+e+f = 31` :: sage: positive_coords = Polyhedron(ieqs=[ ... [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], ... [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]]) sage: P = Polyhedron(ieqs=positive_coords.inequalities() + ( ... [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]]) sage: P A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices sage: P.dim() 5 sage: P.Vrepresentation() (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31), A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0), A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0), A vertex at (0, 0, 0, 31/2, 31/2, 0)) .. NOTE:: * Once constructed, a ``Polyhedron`` object is immutable. * Although the option ``field=RDF`` allows numerical data to be used, it might not give the right answer for degenerate input data - the results can depend upon the tolerance setting of cdd. """ # Clean up the arguments vertices = _make_listlist(vertices) rays = _make_listlist(rays) lines = _make_listlist(lines) ieqs = _make_listlist(ieqs) eqns = _make_listlist(eqns) got_Vrep = (len(vertices + rays + lines) > 0) got_Hrep = (len(ieqs + eqns) > 0) if got_Vrep and got_Hrep: raise ValueError('You cannot specify both H- and V-representation.') elif got_Vrep: deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1] elif got_Hrep: deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1 else: if ambient_dim is None: deduced_ambient_dim = 0 else: deduced_ambient_dim = ambient_dim if base_ring is None: base_ring = ZZ # set ambient_dim if ambient_dim is not None and deduced_ambient_dim != ambient_dim: raise ValueError( 'Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.' ) ambient_dim = deduced_ambient_dim # figure out base_ring from sage.misc.flatten import flatten values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: try: convert = not all(x.parent() is base_ring for x in values) except AttributeError: # No x.parent() method? convert = True else: from sage.rings.integer import is_Integer from sage.rings.rational import is_Rational from sage.rings.real_double import is_RealDoubleElement if all(is_Integer(x) for x in values): if got_Vrep: base_ring = ZZ else: # integral inequalities usually do not determine a lattice polytope! base_ring = QQ convert = False elif all(is_Rational(x) for x in values): base_ring = QQ convert = False elif all(is_RealDoubleElement(x) for x in values): base_ring = RDF convert = False else: try: for v in values: ZZ(v) if got_Vrep: base_ring = ZZ else: base_ring = QQ convert = True except (TypeError, ValueError): from sage.structure.sequence import Sequence values = Sequence(values) common_ring = values.universe() if QQ.has_coerce_map_from(common_ring): base_ring = QQ convert = True elif common_ring is RR: # DWIM: replace with RDF base_ring = RDF convert = True else: base_ring = common_ring convert = True # Add the origin if necesarry if got_Vrep and len(vertices) == 0: vertices = [[0] * ambient_dim] # Specific backends can override the base_ring from sage.geometry.polyhedron.parent import Polyhedra parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() # finally, construct the Polyhedron Hrep = Vrep = None if got_Hrep: Hrep = [ieqs, eqns] if got_Vrep: Vrep = [vertices, rays, lines] return parent(Vrep, Hrep, convert=convert, verbose=verbose)
def Polyhedron(vertices=None, rays=None, lines=None, ieqs=None, eqns=None, ambient_dim=None, base_ring=None, minimize=True, verbose=False, backend=None): """ Construct a polyhedron object. You may either define it with vertex/ray/line or inequalities/equations data, but not both. Redundant data will automatically be removed (unless ``minimize=False``), and the complementary representation will be computed. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of ``base_ring`` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of ``base_ring`` elements. - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`. - ``base_ring`` -- a sub-field of the reals implemented in Sage. The field over which the polyhedron will be defined. For ``QQ`` and algebraic extensions, exact arithmetic will be used. For ``RDF``, floating point numbers will be used. Floating point arithmetic is faster but might give the wrong result for degenerate input. - ``ambient_dim`` -- integer. The ambient space dimension. Usually can be figured out automatically from the H/Vrepresentation dimensions. - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are * ``'cdd'``: use cdd (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or `\RDF` coefficients depending on ``base_ring``. * ``'normaliz'``: use normaliz (:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring``. * ``'polymake'``: use polymake (:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or ``QuadraticField`` coefficients depending on ``base_ring``. * ``'ppl'``: use ppl (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring``. * ``'field'``: use python implementation (:mod:`~sage.geometry.polyhedron.backend_field`) for any field Some backends support further optional arguments: - ``minimize`` -- boolean (default: ``True``). Whether to immediately remove redundant H/V-representation data. Currently not used. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. Only supported by the cdd backends. OUTPUT: The polyhedron defined by the input data. EXAMPLES: Construct some polyhedra:: sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]]) sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]]) sage: list(square_from_ieqs.vertex_generator()) [A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, -1)] sage: list(square_from_vertices.inequality_generator()) [An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0] sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF) sage: p.n_inequalities() 2 The same polyhedron given in two ways:: sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]]) sage: p.Vrepresentation() (A line in the direction (0, 0, 1), A ray in the direction (1, 0, 0), A ray in the direction (0, 1, 0), A vertex at (0, 0, 0)) sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]]) sage: q.Hrepresentation() (An inequality (1, 0, 0) x + 0 >= 0, An inequality (0, 1, 0) x + 0 >= 0) Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with coordinates `a, b, \dots, f` and * The inequality `e+b \geq c+d` * The inequality `e+c \geq b+d` * The equation `a+b+c+d+e+f = 31` :: sage: positive_coords = Polyhedron(ieqs=[ ....: [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], ....: [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]]) sage: P = Polyhedron(ieqs=positive_coords.inequalities() + ( ....: [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]]) sage: P A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices sage: P.dim() 5 sage: P.Vrepresentation() (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31), A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0), A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0), A vertex at (0, 0, 0, 31/2, 31/2, 0)) When the input contains elements of a Number Field, they require an embedding:: sage: K = NumberField(x^2-2,'s') sage: s = K.0 sage: L = NumberField(x^3-2,'t') sage: t = L.0 sage: P = Polyhedron(vertices = [[0,s],[t,0]]) Traceback (most recent call last): ... ValueError: invalid base ring .. NOTE:: * Once constructed, a ``Polyhedron`` object is immutable. * Although the option ``base_ring=RDF`` allows numerical data to be used, it might not give the right answer for degenerate input data - the results can depend upon the tolerance setting of cdd. TESTS: Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`):: sage: f = float(1.1) sage: Polyhedron(vertices=[[f]]) A 0-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex Check that giving ``int`` input gets converted to ``ZZ`` (see :trac:`22605`):: sage: Polyhedron(vertices=[[int(42)]]) A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex Check that giving ``Fraction`` input gets converted to ``QQ`` (see :trac:`22605`):: sage: from fractions import Fraction sage: f = Fraction(int(6), int(8)) sage: Polyhedron(vertices=[[f]]) A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex Check that input with too many bits of precision returns an error (see :trac:`22552`):: sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)]) Traceback (most recent call last): ... ValueError: for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd' Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`):: sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) Traceback (most recent call last): ... ValueError: no appropriate backend for computations with Real Field with 40 bits of precision sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) Traceback (most recent call last): ... ValueError: no appropriate backend for computations with Real Field with 53 bits of precision """ # Clean up the arguments vertices = _make_listlist(vertices) rays = _make_listlist(rays) lines = _make_listlist(lines) ieqs = _make_listlist(ieqs) eqns = _make_listlist(eqns) got_Vrep = (len(vertices + rays + lines) > 0) got_Hrep = (len(ieqs + eqns) > 0) if got_Vrep and got_Hrep: raise ValueError('cannot specify both H- and V-representation.') elif got_Vrep: deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1] elif got_Hrep: deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1 else: if ambient_dim is None: deduced_ambient_dim = 0 else: deduced_ambient_dim = ambient_dim if base_ring is None: base_ring = ZZ # set ambient_dim if ambient_dim is not None and deduced_ambient_dim != ambient_dim: raise ValueError( 'ambient space dimension mismatch. Try removing the "ambient_dim" parameter.' ) ambient_dim = deduced_ambient_dim # figure out base_ring from sage.misc.flatten import flatten from sage.structure.element import parent from sage.categories.all import Rings, Fields values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: convert = any(parent(x) is not base_ring for x in values) elif not values: base_ring = ZZ convert = False else: P = parent(values[0]) if any(parent(x) is not P for x in values): from sage.structure.sequence import Sequence P = Sequence(values).universe() convert = True else: convert = False from sage.structure.coerce import py_scalar_parent if isinstance(P, type): base_ring = py_scalar_parent(P) convert = convert or P is not base_ring else: base_ring = P if not got_Vrep and base_ring not in Fields(): base_ring = base_ring.fraction_field() convert = True if base_ring not in Rings(): raise ValueError('invalid base ring') if not base_ring.is_exact(): # TODO: remove this hack? if base_ring is RR: base_ring = RDF convert = True elif base_ring is not RDF: raise ValueError( "for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd'" ) # Add the origin if necessary if got_Vrep and len(vertices) == 0: vertices = [[0] * ambient_dim] # Specific backends can override the base_ring from sage.geometry.polyhedron.parent import Polyhedra parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() # finally, construct the Polyhedron Hrep = Vrep = None if got_Hrep: Hrep = [ieqs, eqns] if got_Vrep: Vrep = [vertices, rays, lines] return parent(Vrep, Hrep, convert=convert, verbose=verbose)
def Polyhedron(vertices=None, rays=None, lines=None, ieqs=None, eqns=None, ambient_dim=None, base_ring=None, minimize=True, verbose=False, backend=None): """ Construct a polyhedron object. You may either define it with vertex/ray/line or inequalities/equations data, but not both. Redundant data will automatically be removed (unless ``minimize=False``), and the complementary representation will be computed. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of ``base_ring`` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of ``base_ring`` elements. - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`. - ``base_ring`` -- either ``QQ`` or ``RDF``. The field over which the polyhedron will be defined. For ``QQ``, exact arithmetic will be used. For ``RDF``, floating point numbers will be used. Floating point arithmetic is faster but might give the wrong result for degenerate input. - ``ambient_dim`` -- integer. The ambient space dimension. Usually can be figured out automatically from the H/Vrepresentation dimensions. - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are * ``'cdd'``: use cdd (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or `\RDF` coefficients depending on ``base_ring``. * ``'ppl'``: use ppl (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring``. Some backends support further optional arguments: - ``minimize`` -- boolean (default: ``True``). Whether to immediately remove redundant H/V-representation data. Currently not used. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. Only supported by the cdd backends. OUTPUT: The polyhedron defined by the input data. EXAMPLES: Construct some polyhedra:: sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]]) sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]]) sage: list(square_from_ieqs.vertex_generator()) [A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, -1)] sage: list(square_from_vertices.inequality_generator()) [An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0] sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF) sage: p.n_inequalities() 2 The same polyhedron given in two ways:: sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]]) sage: p.Vrepresentation() (A line in the direction (0, 0, 1), A ray in the direction (1, 0, 0), A ray in the direction (0, 1, 0), A vertex at (0, 0, 0)) sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]]) sage: q.Hrepresentation() (An inequality (1, 0, 0) x + 0 >= 0, An inequality (0, 1, 0) x + 0 >= 0) Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with coordinates `a, b, \dots, f` and * The inequality `e+b \geq c+d` * The inequality `e+c \geq b+d` * The equation `a+b+c+d+e+f = 31` :: sage: positive_coords = Polyhedron(ieqs=[ ... [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], ... [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]]) sage: P = Polyhedron(ieqs=positive_coords.inequalities() + ( ... [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]]) sage: P A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices sage: P.dim() 5 sage: P.Vrepresentation() (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31), A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0), A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0), A vertex at (0, 0, 0, 31/2, 31/2, 0)) .. NOTE:: * Once constructed, a ``Polyhedron`` object is immutable. * Although the option ``field=RDF`` allows numerical data to be used, it might not give the right answer for degenerate input data - the results can depend upon the tolerance setting of cdd. """ # Clean up the arguments vertices = _make_listlist(vertices) rays = _make_listlist(rays) lines = _make_listlist(lines) ieqs = _make_listlist(ieqs) eqns = _make_listlist(eqns) got_Vrep = (len(vertices+rays+lines) > 0) got_Hrep = (len(ieqs+eqns) > 0) if got_Vrep and got_Hrep: raise ValueError('You cannot specify both H- and V-representation.') elif got_Vrep: deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1] elif got_Hrep: deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1 else: if ambient_dim is None: deduced_ambient_dim = 0 else: deduced_ambient_dim = ambient_dim if base_ring is None: base_ring = ZZ # set ambient_dim if ambient_dim is not None and deduced_ambient_dim!=ambient_dim: raise ValueError('Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.') ambient_dim = deduced_ambient_dim # figure out base_ring from sage.misc.flatten import flatten values = flatten(vertices+rays+lines+ieqs+eqns) if base_ring is not None: try: convert = not all(x.parent() is base_ring for x in values) except AttributeError: # No x.parent() method? convert = True else: from sage.rings.integer import is_Integer from sage.rings.rational import is_Rational from sage.rings.real_double import is_RealDoubleElement if all(is_Integer(x) for x in values): if got_Vrep: base_ring = ZZ else: # integral inequalities usually do not determine a latice polytope! base_ring = QQ convert=False elif all(is_Rational(x) for x in values): base_ring = QQ convert=False elif all(is_RealDoubleElement(x) for x in values): base_ring = RDF convert=False else: try: map(ZZ, values) if got_Vrep: base_ring = ZZ else: base_ring = QQ convert = True except TypeError: from sage.structure.sequence import Sequence values = Sequence(values) if QQ.has_coerce_map_from(values.universe()): base_ring = QQ convert = True else: base_ring = RDF convert = True # Add the origin if necesarry if got_Vrep and len(vertices)==0: vertices = [ [0]*ambient_dim ] # Specific backends can override the base_ring from sage.geometry.polyhedron.parent import Polyhedra parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() # Convert into base_ring if necessary def convert_base_ring(lstlst): return [ [base_ring(x) for x in lst] for lst in lstlst] Hrep = Vrep = None if got_Hrep: Hrep = [ieqs, eqns] if got_Vrep: Vrep = [vertices, rays, lines] # finally, construct the Polyhedron return parent(Vrep, Hrep, convert=convert)
def Polyhedron(vertices=None, rays=None, lines=None, ieqs=None, eqns=None, ambient_dim=None, base_ring=None, minimize=True, verbose=False, backend=None, mutable=False): r""" Construct a polyhedron object. You may either define it with vertex/ray/line or inequalities/equations data, but not both. Redundant data will automatically be removed (unless ``minimize=False``), and the complementary representation will be computed. INPUT: - ``vertices`` -- list of points. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of ``base_ring`` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of ``base_ring`` elements. - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`. - ``base_ring`` -- a sub-field of the reals implemented in Sage. The field over which the polyhedron will be defined. For ``QQ`` and algebraic extensions, exact arithmetic will be used. For ``RDF``, floating point numbers will be used. Floating point arithmetic is faster but might give the wrong result for degenerate input. - ``ambient_dim`` -- integer. The ambient space dimension. Usually can be figured out automatically from the H/Vrepresentation dimensions. - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are * ``'cdd'``: use cdd (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or `\RDF` coefficients depending on ``base_ring`` * ``'normaliz'``: use normaliz (:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring`` * ``'polymake'``: use polymake (:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or ``QuadraticField`` coefficients depending on ``base_ring`` * ``'ppl'``: use ppl (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or `\QQ` coefficients depending on ``base_ring`` * ``'field'``: use python implementation (:mod:`~sage.geometry.polyhedron.backend_field`) for any field Some backends support further optional arguments: - ``minimize`` -- boolean (default: ``True``); whether to immediately remove redundant H/V-representation data; currently not used. - ``verbose`` -- boolean (default: ``False``); whether to print verbose output for debugging purposes; only supported by the cdd and normaliz backends - ``mutable`` -- boolean (default: ``False``); whether the polyhedron is mutable OUTPUT: The polyhedron defined by the input data. EXAMPLES: Construct some polyhedra:: sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]]) sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]]) sage: list(square_from_ieqs.vertex_generator()) [A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, -1)] sage: list(square_from_vertices.inequality_generator()) [An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0] sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF) sage: p.n_inequalities() 2 The same polyhedron given in two ways:: sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]]) sage: p.Vrepresentation() (A line in the direction (0, 0, 1), A ray in the direction (1, 0, 0), A ray in the direction (0, 1, 0), A vertex at (0, 0, 0)) sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]]) sage: q.Hrepresentation() (An inequality (1, 0, 0) x + 0 >= 0, An inequality (0, 1, 0) x + 0 >= 0) Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with coordinates `a, b, \dots, f` and * The inequality `e+b \geq c+d` * The inequality `e+c \geq b+d` * The equation `a+b+c+d+e+f = 31` :: sage: positive_coords = Polyhedron(ieqs=[ ....: [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], ....: [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]]) sage: P = Polyhedron(ieqs=positive_coords.inequalities() + ( ....: [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]]) sage: P A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices sage: P.dim() 5 sage: P.Vrepresentation() (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31), A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0), A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0), A vertex at (0, 0, 0, 31/2, 31/2, 0)) Regular icosahedron, centered at `0` with edge length `2`, with vertices given by the cyclic shifts of `(0, \pm 1, \pm (1+\sqrt(5))/2)`, cf. :wikipedia:`Regular_icosahedron`. It needs a number field:: sage: R0.<r0> = QQ[] # optional - sage.rings.number_field sage: R1.<r1> = NumberField(r0^2-5, embedding=AA(5)**(1/2)) # optional - sage.rings.number_field sage: gold = (1+r1)/2 # optional - sage.rings.number_field sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] # optional - sage.rings.number_field sage: pp = Permutation((1, 2, 3)) # optional - sage.combinat # optional - sage.rings.number_field sage: icosah = Polyhedron( # optional - sage.combinat # optional - sage.rings.number_field ....: [(pp^2).action(w) for w in v] + [pp.action(w) for w in v] + v, ....: base_ring=R1) sage: len(icosah.faces(2)) # optional - sage.combinat # optional - sage.rings.number_field 20 When the input contains elements of a Number Field, they require an embedding:: sage: K = NumberField(x^2-2,'s') # optional - sage.rings.number_field sage: s = K.0 # optional - sage.rings.number_field sage: L = NumberField(x^3-2,'t') # optional - sage.rings.number_field sage: t = L.0 # optional - sage.rings.number_field sage: P = Polyhedron(vertices = [[0,s],[t,0]]) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: invalid base ring Create a mutable polyhedron:: sage: P = Polyhedron(vertices=[[0, 1], [1, 0]], mutable=True) sage: P.is_mutable() True sage: hasattr(P, "_Vrepresentation") False sage: P.Vrepresentation() (A vertex at (0, 1), A vertex at (1, 0)) sage: hasattr(P, "_Vrepresentation") True .. NOTE:: * Once constructed, a ``Polyhedron`` object is immutable. * Although the option ``base_ring=RDF`` allows numerical data to be used, it might not give the right answer for degenerate input data - the results can depend upon the tolerance setting of cdd. TESTS: Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`):: sage: f = float(1.1) sage: Polyhedron(vertices=[[f]]) A 0-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex Check that giving ``int`` input gets converted to ``ZZ`` (see :trac:`22605`):: sage: Polyhedron(vertices=[[int(42)]]) A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex Check that giving ``Fraction`` input gets converted to ``QQ`` (see :trac:`22605`):: sage: from fractions import Fraction sage: f = Fraction(int(6), int(8)) sage: Polyhedron(vertices=[[f]]) A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex Check that non-compact polyhedra given by V-representation have base ring ``QQ``, not ``ZZ`` (see :trac:`27840`):: sage: Q = Polyhedron(vertices=[(1, 2, 3), (1, 3, 2), (2, 1, 3), ....: (2, 3, 1), (3, 1, 2), (3, 2, 1)], ....: rays=[[1, 1, 1]], lines=[[1, 2, 3]], backend='ppl') sage: Q.base_ring() Rational Field Check that enforcing base ring `ZZ` for this example gives an error:: sage: Q = Polyhedron(vertices=[(1, 2, 3), (1, 3, 2), (2, 1, 3), ....: (2, 3, 1), (3, 1, 2), (3, 2, 1)], ....: rays=[[1, 1, 1]], lines=[[1, 2, 3]], backend='ppl', ....: base_ring=ZZ) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer Check that input with too many bits of precision returns an error (see :trac:`22552`):: sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)]) Traceback (most recent call last): ... ValueError: the only allowed inexact ring is 'RDF' with backend 'cdd' Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`):: sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40)) Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 40 bits of precision sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53)) Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 53 bits of precision Check that :trac:`17339` is fixed:: sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ) The empty polyhedron in QQ^0 sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[], base_ring=QQ); P A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex sage: P.Vrepresentation() (A vertex at (),) sage: Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines sage: Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ, backend='field') A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="cdd") The empty polyhedron in QQ^0 sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="ppl") The empty polyhedron in QQ^0 sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="field") The empty polyhedron in QQ^0 sage: Polyhedron(ambient_dim=2, vertices=[], rays=[], lines=[], base_ring=QQ) The empty polyhedron in QQ^2 .. SEEALSO:: :mod:`Library of polytopes <sage.geometry.polyhedron.library>` """ got_Vrep = not ((vertices is None) and (rays is None) and (lines is None)) got_Hrep = not ((ieqs is None) and (eqns is None)) # Clean up the arguments vertices = _make_listlist(vertices) rays = _make_listlist(rays) lines = _make_listlist(lines) ieqs = _make_listlist(ieqs) eqns = _make_listlist(eqns) if got_Vrep and got_Hrep: raise ValueError('cannot specify both H- and V-representation.') elif got_Vrep: deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1] if deduced_ambient_dim is None: if ambient_dim is not None: deduced_ambient_dim = ambient_dim else: deduced_ambient_dim = 0 elif got_Hrep: deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] if deduced_ambient_dim is None: if ambient_dim is not None: deduced_ambient_dim = ambient_dim else: deduced_ambient_dim = 0 else: deduced_ambient_dim -= 1 else: if ambient_dim is None: deduced_ambient_dim = 0 else: deduced_ambient_dim = ambient_dim if base_ring is None: base_ring = ZZ # set ambient_dim if ambient_dim is not None and deduced_ambient_dim != ambient_dim: raise ValueError( 'ambient space dimension mismatch. Try removing the "ambient_dim" parameter.' ) ambient_dim = deduced_ambient_dim # figure out base_ring from sage.misc.flatten import flatten from sage.structure.element import parent from sage.categories.fields import Fields from sage.categories.rings import Rings values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: convert = any(parent(x) is not base_ring for x in values) elif not values: base_ring = ZZ convert = False else: P = parent(values[0]) if any(parent(x) is not P for x in values): from sage.structure.sequence import Sequence P = Sequence(values).universe() convert = True else: convert = False from sage.structure.coerce import py_scalar_parent if isinstance(P, type): base_ring = py_scalar_parent(P) convert = convert or P is not base_ring else: base_ring = P if base_ring not in Fields(): got_compact_Vrep = got_Vrep and not rays and not lines got_cone_Vrep = got_Vrep and all( all(x == 0 for x in v) for v in vertices) if not got_compact_Vrep and not got_cone_Vrep: base_ring = base_ring.fraction_field() convert = True if base_ring not in Rings(): raise ValueError('invalid base ring') try: from sage.symbolic.ring import SR except ImportError: SR = None if base_ring is not SR and not base_ring.is_exact(): # TODO: remove this hack? if base_ring is RR: base_ring = RDF convert = True elif base_ring is not RDF: raise ValueError( "the only allowed inexact ring is 'RDF' with backend 'cdd'" ) # Add the origin if necessary if got_Vrep and len(vertices) == 0 and len(rays + lines) > 0: vertices = [[0] * ambient_dim] # Specific backends can override the base_ring from sage.geometry.polyhedron.parent import Polyhedra parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() # finally, construct the Polyhedron Hrep = Vrep = None if got_Hrep: Hrep = [ieqs, eqns] if got_Vrep: Vrep = [vertices, rays, lines] return parent(Vrep, Hrep, convert=convert, verbose=verbose, mutable=mutable)