def rays_from_constraints(self, halfspaces): # Create PPL variables. x = [Variable(i) for i in range(self.dim)] # Init constraint system. constraints = Constraint_System() # Add polytope facets to constraint systems. # Format of ConvexHull.equations: [a1 a2 .. b] => a1*x1 + a2*x2 + .. + b <= 0. for hyp, orient in halfspaces: # PPL works on integral values, so all # coordinates are scaled and truncated. if orient == -1: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b <= 0) elif orient == 1: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b >= 0) elif orient == 0: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b == 0) # Build PPL polyhedra. poly = C_Polyhedron(constraints) # Get vertices of polytope resulting from intersection. only rays rays = [] for gen in poly.minimized_generators(): if gen.is_ray(): ray = np.array(gen.coefficients()).astype(float) ray = ray / np.linalg.norm(ray) rays.append(ray) return np.array(rays)
def contains(self, point_coordinates): r""" Test whether point is contained in the polytope. INPUT: - ``point_coordinates`` -- a list/tuple/iterable of rational numbers. The coordinates of the point. OUTPUT: Boolean. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: line = LatticePolytope_PPL((1,2,3), (-1,-2,-3)) sage: line.contains([0,0,0]) True sage: line.contains([1,0,0]) False """ p = C_Polyhedron(point(Linear_Expression(list(point_coordinates), 1))) is_included = Poly_Con_Relation.is_included() for c in self.constraints(): if not p.relation_with(c).implies(is_included): return False return True
def contains(self, point_coordinates): r""" Test whether point is contained in the polytope. INPUT: - ``point_coordinates`` -- a list/tuple/iterable of rational numbers. The coordinates of the point. OUTPUT: Boolean. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: line = LatticePolytope_PPL((1,2,3), (-1,-2,-3)) sage: line.contains([0,0,0]) True sage: line.contains([1,0,0]) False """ p = C_Polyhedron(point(Linear_Expression(list(point_coordinates), 1))) is_included = Poly_Con_Relation.is_included() for c in self.constraints(): if not p.relation_with(c).implies(is_included): return False return True
def has_IP_property(self): """ Whether the lattice polytope has the IP property. That is, the polytope is full-dimensional and the origin is a interior point not on the boundary. OUTPUT: Boolean. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((-1,-1),(0,1),(1,0)).has_IP_property() True sage: LatticePolytope_PPL((-1,-1),(1,1)).has_IP_property() False """ origin = C_Polyhedron(point(0*Variable(self.space_dimension()))) is_included = Poly_Con_Relation.is_included() saturates = Poly_Con_Relation.saturates() for c in self.constraints(): rel = origin.relation_with(c) if (not rel.implies(is_included)) or rel.implies(saturates): return False return True
def vertices_saturating(self, constraint): r""" Return the vertices saturating the constraint INPUT: - ``constraint`` -- a constraint (inequality or equation) of the polytope. OUTPUT: The tuple of vertices saturating the constraint. The vertices are returned as `\ZZ`-vectors, as in :meth:`vertices`. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((0,0),(0,1),(1,0)) sage: ieq = next(iter(p.constraints())); ieq x0>=0 sage: p.vertices_saturating(ieq) ((0, 0), (0, 1)) """ from ppl import C_Polyhedron, Poly_Con_Relation result = [] for i,v in enumerate(self.minimized_generators()): v = C_Polyhedron(v) if v.relation_with(constraint).implies(Poly_Con_Relation.saturates()): result.append(self.vertices()[i]) return tuple(result)
def has_IP_property(self): """ Whether the lattice polytope has the IP property. That is, the polytope is full-dimensional and the origin is a interior point not on the boundary. OUTPUT: Boolean. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: LatticePolytope_PPL((-1,-1),(0,1),(1,0)).has_IP_property() True sage: LatticePolytope_PPL((-1,-1),(1,1)).has_IP_property() False """ origin = C_Polyhedron(point(0*Variable(self.space_dimension()))) is_included = Poly_Con_Relation.is_included() saturates = Poly_Con_Relation.saturates() for c in self.constraints(): rel = origin.relation_with(c) if (not rel.implies(is_included)) or rel.implies(saturates): return False return True
def vertices_saturating(self, constraint): r""" Return the vertices saturating the constraint INPUT: - ``constraint`` -- a constraint (inequality or equation) of the polytope. OUTPUT: The tuple of vertices saturating the constraint. The vertices are returned as `\ZZ`-vectors, as in :meth:`vertices`. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((0,0),(0,1),(1,0)) sage: ieq = next(iter(p.constraints())); ieq x0>=0 sage: p.vertices_saturating(ieq) ((0, 0), (0, 1)) """ from ppl import C_Polyhedron, Poly_Con_Relation result = [] for i,v in enumerate(self.minimized_generators()): v = C_Polyhedron(v) if v.relation_with(constraint).implies(Poly_Con_Relation.saturates()): result.append(self.vertices()[i]) return tuple(result)
def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Vrepresentation(p, [], [], []) """ gs = Generator_System() if vertices is None: vertices = [] for v in vertices: d = LCM_list([denominator(v_i) for v_i in v]) if d.is_one(): gs.insert(point(Linear_Expression(v, 0))) else: dv = [ d*v_i for v_i in v ] gs.insert(point(Linear_Expression(dv, 0), d)) if rays is None: rays = [] for r in rays: d = LCM_list([denominator(r_i) for r_i in r]) if d.is_one(): gs.insert(ray(Linear_Expression(r, 0))) else: dr = [ d*r_i for r_i in r ] gs.insert(ray(Linear_Expression(dr, 0))) if lines is None: lines = [] for l in lines: d = LCM_list([denominator(l_i) for l_i in l]) if d.is_one(): gs.insert(line(Linear_Expression(l, 0))) else: dl = [ d*l_i for l_i in l ] gs.insert(line(Linear_Expression(dl, 0))) if gs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') else: self._ppl_polyhedron = C_Polyhedron(gs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize)
def position(self, hyperplane): x = [Variable(i) for i in range(self.dim)] p = C_Polyhedron(Generator_System(self.ppl)) s_rel = p.relation_with( sum(hyperplane.a[i] * x[i] for i in range(self.dim)) + hyperplane.b < 0) if s_rel.implies(Poly_Con_Relation.is_included()): return -1 else: b_rel = p.relation_with( sum(hyperplane.a[i] * x[i] for i in range(self.dim)) + hyperplane.b > 0) if b_rel.implies(Poly_Con_Relation.is_included()): return 1 else: return 0
def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ Construct polyhedron from H-representation data. INPUT: - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Hrepresentation(p, [], []) """ cs = Constraint_System() if ieqs is None: ieqs = [] for ieq in ieqs: d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) dieq = [ZZ(d * ieq_i) for ieq_i in ieq] b = dieq[0] A = dieq[1:] cs.insert(Linear_Expression(A, b) >= 0) if eqns is None: eqns = [] for eqn in eqns: d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) deqn = [ZZ(d * eqn_i) for eqn_i in eqn] b = deqn[0] A = deqn[1:] cs.insert(Linear_Expression(A, b) == 0) if cs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') else: self._ppl_polyhedron = C_Polyhedron(cs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize)
def __call__(self, x): """ Return the image of ``x`` INPUT: - ``x`` -- a vector or lattice polytope. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL, C_Polyhedron sage: from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticeEuclideanGroupElement sage: M = LatticeEuclideanGroupElement([[1,2],[2,3],[-1,2]], [1,2,3]) sage: M(vector(ZZ, [11,13])) (38, 63, 18) sage: M(LatticePolytope_PPL((0,0),(1,0),(0,1))) A 2-dimensional lattice polytope in ZZ^3 with 3 vertices """ from sage.geometry.polyhedron.ppl_lattice_polytope import ( LatticePolytope_PPL, LatticePolytope_PPL_class) if isinstance(x, LatticePolytope_PPL_class): if x.is_empty(): from ppl import C_Polyhedron return LatticePolytope_PPL( C_Polyhedron(self._b.degree(), 'empty')) return LatticePolytope_PPL(*[self(v) for v in x.vertices()]) v = self._A * x + self._b v.set_immutable() return v
def _init_empty_polyhedron(self): """ Initializes an empty polyhedron. TESTS:: sage: empty = Polyhedron(backend='ppl'); empty The empty polyhedron in ZZ^0 sage: empty.Vrepresentation() () sage: empty.Hrepresentation() (An equation -1 == 0,) sage: Polyhedron(vertices = [], backend='ppl') The empty polyhedron in ZZ^0 sage: Polyhedron(backend='ppl')._init_empty_polyhedron() """ super(Polyhedron_ppl, self)._init_empty_polyhedron() self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty')
def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ Construct polyhedron from H-representation data. INPUT: - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Hrepresentation(p, [], []) """ cs = Constraint_System() if ieqs is None: ieqs = [] for ieq in ieqs: d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) dieq = [ ZZ(d*ieq_i) for ieq_i in ieq ] b = dieq[0] A = dieq[1:] cs.insert(Linear_Expression(A, b) >= 0) if eqns is None: eqns = [] for eqn in eqns: d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) deqn = [ ZZ(d*eqn_i) for eqn_i in eqn ] b = deqn[0] A = deqn[1:] cs.insert(Linear_Expression(A, b) == 0) if cs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') else: self._ppl_polyhedron = C_Polyhedron(cs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize)
def solve_les(hyperplanes): dim = len(hyperplanes[0]) - 1 x = [Variable(i) for i in range(dim)] constraints = Constraint_System() for hyp in hyperplanes: constraints.insert( sum(hyp[i + 1] * x[i] for i in range(dim)) + hyp[0] == 0) poly = C_Polyhedron(constraints) ppl_points = [pt for pt in poly.minimized_generators() if pt.is_point()] if len(ppl_points) != len(poly.minimized_generators()): # Not uniquely determined. return None if len(ppl_points) == 1: vertex = Vertex( tuple(c / ppl_points[0].divisor() for c in ppl_points[0].coefficients()), None) return vertex elif len(ppl_points) == 0: return None else: raise ValueError
def poly_from_vertices(self, vertices): # Create PPL variables. x = [Variable(i) for i in range(self.dim)] # Init constraint system. generators = Generator_System() # ppl needs coordinates in form of point(sum(a_i *x_i), denom) with a_i integers for vertex in vertices: generators.insert(vertex.ppl) # Build PPL polyhedra. return C_Polyhedron(generators)
def __init__(self, halfspaces=None, vertices=None): if halfspaces is not None: self.halfspaces = halfspaces self.dim = halfspaces[0][0].dim self.poly = self.poly_from_constraints(halfspaces) self.vertices = self.vertices_from_poly() elif vertices is not None: v = vertices.pop() self.dim = v.dim vertices.add(v) self.poly = self.poly_from_vertices(vertices) self.vertices = self.vertices_from_poly() self.hyperplanes = self.hyperplanes_from_poly() self.halfspaces = zip(self.hyperplanes, [1] * len(self.hyperplanes)) else: self.hyperplanes = [] self.halfspaces = [] self.vertices = [] self.poly = C_Polyhedron(0)
def _init_empty_polyhedron(self): """ Initializes an empty polyhedron. TESTS:: sage: empty = Polyhedron(backend='ppl'); empty The empty polyhedron in ZZ^0 sage: empty.Vrepresentation() () sage: empty.Hrepresentation() (An equation -1 == 0,) sage: Polyhedron(vertices = [], backend='ppl') The empty polyhedron in ZZ^0 sage: Polyhedron(backend='ppl')._init_empty_polyhedron() """ super(Polyhedron_ppl, self)._init_empty_polyhedron() self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty')
def poly_from_constraints(self, halfspaces): # Create PPL variables. x = [Variable(i) for i in range(self.dim)] # Init constraint system. constraints = Constraint_System() # Add polytope facets to constraint systems. # Format of ConvexHull.equations: [a1 a2 .. b] => a1*x1 + a2*x2 + .. + b <= 0. for hyp, orient in halfspaces: if orient == -1: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b <= 0) elif orient == 1: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b >= 0) elif orient == 0: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b == 0) # Build PPL polyhedra. return C_Polyhedron(constraints)
class Polyhedron_ppl(Polyhedron_base): """ Polyhedra with ppl INPUT: - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``. - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. EXAMPLES:: sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], rays=[(1,1)], lines=[], backend='ppl') sage: TestSuite(p).run() """ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Vrepresentation(p, [], [], []) """ gs = Generator_System() if vertices is None: vertices = [] for v in vertices: d = LCM_list([denominator(v_i) for v_i in v]) if d.is_one(): gs.insert(point(Linear_Expression(v, 0))) else: dv = [d * v_i for v_i in v] gs.insert(point(Linear_Expression(dv, 0), d)) if rays is None: rays = [] for r in rays: d = LCM_list([denominator(r_i) for r_i in r]) if d.is_one(): gs.insert(ray(Linear_Expression(r, 0))) else: dr = [d * r_i for r_i in r] gs.insert(ray(Linear_Expression(dr, 0))) if lines is None: lines = [] for l in lines: d = LCM_list([denominator(l_i) for l_i in l]) if d.is_one(): gs.insert(line(Linear_Expression(l, 0))) else: dl = [d * l_i for l_i in l] gs.insert(line(Linear_Expression(dl, 0))) if gs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') else: self._ppl_polyhedron = C_Polyhedron(gs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ Construct polyhedron from H-representation data. INPUT: - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Hrepresentation(p, [], []) """ cs = Constraint_System() if ieqs is None: ieqs = [] for ieq in ieqs: d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) dieq = [ZZ(d * ieq_i) for ieq_i in ieq] b = dieq[0] A = dieq[1:] cs.insert(Linear_Expression(A, b) >= 0) if eqns is None: eqns = [] for eqn in eqns: d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) deqn = [ZZ(d * eqn_i) for eqn_i in eqn] b = deqn[0] A = deqn[1:] cs.insert(Linear_Expression(A, b) == 0) if cs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') else: self._ppl_polyhedron = C_Polyhedron(cs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize) def _init_Vrepresentation_from_ppl(self, minimize): """ Create the Vrepresentation objects from the ppl polyhedron. EXAMPLES:: sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], ....: backend='ppl') # indirect doctest sage: p.Hrepresentation() (An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (-5, 12) x + 10 >= 0) sage: p._ppl_polyhedron.minimized_constraints() Constraint_System {x0+4*x1-2>=0, x0-12*x1+6>=0, -5*x0+12*x1+10>=0} sage: p.Vrepresentation() (A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)) sage: p._ppl_polyhedron.minimized_generators() Generator_System {point(0/2, 1/2), point(2/1, 0/1), point(24/6, 5/6)} """ self._Vrepresentation = [] gs = self._ppl_polyhedron.minimized_generators() parent = self.parent() for g in gs: coefficients = [Integer(mpz) for mpz in g.coefficients()] if g.is_point(): d = Integer(g.divisor()) if d.is_one(): parent._make_Vertex(self, coefficients) else: parent._make_Vertex(self, [x / d for x in coefficients]) elif g.is_ray(): parent._make_Ray(self, coefficients) elif g.is_line(): parent._make_Line(self, coefficients) else: assert False self._Vrepresentation = tuple(self._Vrepresentation) def _init_Hrepresentation_from_ppl(self, minimize): """ Create the Hrepresentation objects from the ppl polyhedron. EXAMPLES:: sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], ....: backend='ppl') # indirect doctest sage: p.Hrepresentation() (An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (-5, 12) x + 10 >= 0) sage: p._ppl_polyhedron.minimized_constraints() Constraint_System {x0+4*x1-2>=0, x0-12*x1+6>=0, -5*x0+12*x1+10>=0} sage: p.Vrepresentation() (A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)) sage: p._ppl_polyhedron.minimized_generators() Generator_System {point(0/2, 1/2), point(2/1, 0/1), point(24/6, 5/6)} """ self._Hrepresentation = [] cs = self._ppl_polyhedron.minimized_constraints() parent = self.parent() for c in cs: if c.is_inequality(): parent._make_Inequality(self, (c.inhomogeneous_term(), ) + c.coefficients()) elif c.is_equality(): parent._make_Equation(self, (c.inhomogeneous_term(), ) + c.coefficients()) self._Hrepresentation = tuple(self._Hrepresentation) def _init_empty_polyhedron(self): """ Initializes an empty polyhedron. TESTS:: sage: empty = Polyhedron(backend='ppl'); empty The empty polyhedron in ZZ^0 sage: empty.Vrepresentation() () sage: empty.Hrepresentation() (An equation -1 == 0,) sage: Polyhedron(vertices = [], backend='ppl') The empty polyhedron in ZZ^0 sage: Polyhedron(backend='ppl')._init_empty_polyhedron() """ super(Polyhedron_ppl, self)._init_empty_polyhedron() self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty')
def fibration_generator(self, dim): """ Generate the lattice polytope fibrations. For the purposes of this function, a lattice polytope fiber is a sub-lattice polytope. Projecting the plane spanned by the subpolytope to a point yields another lattice polytope, the base of the fibration. INPUT: - ``dim`` -- integer. The dimension of the lattice polytope fiber. OUTPUT: A generator yielding the distinct lattice polytope fibers of given dimension. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: list( p.fibration_generator(2) ) [A 2-dimensional lattice polytope in ZZ^4 with 3 vertices] """ assert self.is_full_dimensional() # "points" are the potential vertices of the fiber. They are # in the $codim$-skeleton of the polytope, which is contained # in the points that saturate at least $dim$ equations. points = [ p for p in self._integral_points_saturating() if len(p[1])>=dim ] points = sorted(points, key=lambda x:len(x[1])) # iterate over point combinations subject to all points being on one facet. def point_combinations_iterator(n, i0=0, saturated=None): for i in range(i0, len(points)): p, ieqs = points[i] if saturated is None: saturated_ieqs = ieqs else: saturated_ieqs = saturated.intersection(ieqs) if len(saturated_ieqs)==0: continue if n == 1: yield [i] else: for c in point_combinations_iterator(n-1, i+1, saturated_ieqs): yield [i] + c point_lines = [ line(Linear_Expression(p[0].list(),0)) for p in points ] origin = point() fibers = set() gs = Generator_System() for indices in point_combinations_iterator(dim): gs.clear() gs.insert(origin) for i in indices: gs.insert(point_lines[i]) plane = C_Polyhedron(gs) if plane.affine_dimension() != dim: continue plane.intersection_assign(self) if (not self.is_full_dimensional()) and (plane.affine_dimension() != dim): continue try: fiber = LatticePolytope_PPL(plane) except TypeError: # not a lattice polytope continue fiber_vertices = tuple(sorted(fiber.vertices())) if fiber_vertices not in fibers: yield fiber fibers.update([fiber_vertices])
import numpy as np from bellpolytope import BellPolytope from bellscenario import BellScenario from bellpolytopewithonewaycomm import BellPolytopeWithOneWayCommunication from ppl import Variable, Generator_System, C_Polyhedron, point from sequentialbellpolytope import SequentialBellPolytope from sequentialbellscenario import SequentialBellScenario if __name__ == '__main__': outputsAliceSeq = [[2, 2], [2, 2]] outputsBob = [2, 2] scenario = SequentialBellScenario(outputsAliceSeq, outputsBob) variables = [Variable(i) for i in range(len(scenario.getTuplesOfEvents()))] gs = Generator_System() for v in BellPolytopeWithOneWayCommunication( SequentialBellPolytope(scenario)).getGeneratorForVertices(): prob = v.getProbabilityList() gs.insert(point(sum(prob[i] * variables[i] for i in range(len(prob))))) poly = C_Polyhedron(gs) constraints = poly.constraints() for constraint in constraints: inequality = str(constraint.inhomogeneous_term().__float__()) + ' ' for coef in constraint.coefficients(): inequality = inequality + str(-coef.__float__()) + ' ' print(inequality)
def find_isomorphism(self, polytope): r""" Return a lattice isomorphism with ``polytope``. INPUT: - ``polytope`` -- a polytope, potentially higher-dimensional. OUTPUT: A :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticeEuclideanGroupElement`. It is not necessarily invertible if the affine dimension of ``self`` or ``polytope`` is not two. A :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticePolytopesNotIsomorphicError` is raised if no such isomorphism exists. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: L1 = LatticePolytope_PPL((1,0),(0,1),(0,0)) sage: L2 = LatticePolytope_PPL((1,0,3),(0,1,0),(0,0,1)) sage: iso = L1.find_isomorphism(L2) sage: iso(L1) == L2 True sage: L1 = LatticePolytope_PPL((0, 1), (3, 0), (0, 3), (1, 0)) sage: L2 = LatticePolytope_PPL((0,0,2,1),(0,1,2,0),(2,0,0,3),(2,3,0,0)) sage: iso = L1.find_isomorphism(L2) sage: iso(L1) == L2 True The following polygons are isomorphic over `\QQ`, but not as lattice polytopes:: sage: L1 = LatticePolytope_PPL((1,0),(0,1),(-1,-1)) sage: L2 = LatticePolytope_PPL((0, 0), (0, 1), (1, 0)) sage: L1.find_isomorphism(L2) Traceback (most recent call last): ... LatticePolytopesNotIsomorphicError: different number of integral points sage: L2.find_isomorphism(L1) Traceback (most recent call last): ... LatticePolytopesNotIsomorphicError: different number of integral points """ from sage.geometry.polyhedron.lattice_euclidean_group_element import \ LatticePolytopesNotIsomorphicError if polytope.affine_dimension() != self.affine_dimension(): raise LatticePolytopesNotIsomorphicError('different dimension') polytope_vertices = polytope.vertices() if len(polytope_vertices) != self.n_vertices(): raise LatticePolytopesNotIsomorphicError( 'different number of vertices') self_vertices = self.ordered_vertices() if len(polytope.integral_points()) != len(self.integral_points()): raise LatticePolytopesNotIsomorphicError( 'different number of integral points') if len(self_vertices) < 3: return self._find_isomorphism_degenerate(polytope) polytope_origin = polytope_vertices[0] origin_P = C_Polyhedron(next(iter(polytope.minimized_generators()))) neighbors = [] for c in polytope.minimized_constraints(): if not c.is_inequality(): continue if origin_P.relation_with(c).implies( Poly_Con_Relation.saturates()): for i, g in enumerate(polytope.minimized_generators()): if i == 0: continue g = C_Polyhedron(g) if g.relation_with(c).implies( Poly_Con_Relation.saturates()): neighbors.append(polytope_vertices[i]) break p_ray_left = neighbors[0] - polytope_origin p_ray_right = neighbors[1] - polytope_origin try: return self._find_cyclic_isomorphism_matching_edge( polytope, polytope_origin, p_ray_left, p_ray_right) except LatticePolytopesNotIsomorphicError: pass try: return self._find_cyclic_isomorphism_matching_edge( polytope, polytope_origin, p_ray_right, p_ray_left) except LatticePolytopesNotIsomorphicError: pass raise LatticePolytopesNotIsomorphicError('different polygons')
class Polyhedron_ppl(Polyhedron_base): """ Polyhedra with ppl INPUT: - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``. - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. EXAMPLES:: sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], rays=[(1,1)], lines=[], backend='ppl') sage: TestSuite(p).run() """ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Vrepresentation(p, [], [], []) """ gs = Generator_System() if vertices is None: vertices = [] for v in vertices: d = LCM_list([denominator(v_i) for v_i in v]) if d.is_one(): gs.insert(point(Linear_Expression(v, 0))) else: dv = [ d*v_i for v_i in v ] gs.insert(point(Linear_Expression(dv, 0), d)) if rays is None: rays = [] for r in rays: d = LCM_list([denominator(r_i) for r_i in r]) if d.is_one(): gs.insert(ray(Linear_Expression(r, 0))) else: dr = [ d*r_i for r_i in r ] gs.insert(ray(Linear_Expression(dr, 0))) if lines is None: lines = [] for l in lines: d = LCM_list([denominator(l_i) for l_i in l]) if d.is_one(): gs.insert(line(Linear_Expression(l, 0))) else: dl = [ d*l_i for l_i in l ] gs.insert(line(Linear_Expression(dl, 0))) if gs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') else: self._ppl_polyhedron = C_Polyhedron(gs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ Construct polyhedron from H-representation data. INPUT: - ``ieqs`` -- list of inequalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``eqns`` -- list of equalities. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Hrepresentation(p, [], []) """ cs = Constraint_System() if ieqs is None: ieqs = [] for ieq in ieqs: d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) dieq = [ ZZ(d*ieq_i) for ieq_i in ieq ] b = dieq[0] A = dieq[1:] cs.insert(Linear_Expression(A, b) >= 0) if eqns is None: eqns = [] for eqn in eqns: d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) deqn = [ ZZ(d*eqn_i) for eqn_i in eqn ] b = deqn[0] A = deqn[1:] cs.insert(Linear_Expression(A, b) == 0) if cs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'universe') else: self._ppl_polyhedron = C_Polyhedron(cs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize) def _init_Vrepresentation_from_ppl(self, minimize): """ Create the Vrepresentation objects from the ppl polyhedron. EXAMPLES:: sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], ....: backend='ppl') # indirect doctest sage: p.Hrepresentation() (An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (-5, 12) x + 10 >= 0) sage: p._ppl_polyhedron.minimized_constraints() Constraint_System {x0+4*x1-2>=0, x0-12*x1+6>=0, -5*x0+12*x1+10>=0} sage: p.Vrepresentation() (A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)) sage: p._ppl_polyhedron.minimized_generators() Generator_System {point(0/2, 1/2), point(2/1, 0/1), point(24/6, 5/6)} """ self._Vrepresentation = [] gs = self._ppl_polyhedron.minimized_generators() parent = self.parent() for g in gs: coefficients = [Integer(mpz) for mpz in g.coefficients()] if g.is_point(): d = Integer(g.divisor()) if d.is_one(): parent._make_Vertex(self, coefficients) else: parent._make_Vertex(self, [x/d for x in coefficients]) elif g.is_ray(): parent._make_Ray(self, coefficients) elif g.is_line(): parent._make_Line(self, coefficients) else: assert False self._Vrepresentation = tuple(self._Vrepresentation) def _init_Hrepresentation_from_ppl(self, minimize): """ Create the Hrepresentation objects from the ppl polyhedron. EXAMPLES:: sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], ....: backend='ppl') # indirect doctest sage: p.Hrepresentation() (An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (-5, 12) x + 10 >= 0) sage: p._ppl_polyhedron.minimized_constraints() Constraint_System {x0+4*x1-2>=0, x0-12*x1+6>=0, -5*x0+12*x1+10>=0} sage: p.Vrepresentation() (A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)) sage: p._ppl_polyhedron.minimized_generators() Generator_System {point(0/2, 1/2), point(2/1, 0/1), point(24/6, 5/6)} """ self._Hrepresentation = [] cs = self._ppl_polyhedron.minimized_constraints() parent = self.parent() for c in cs: if c.is_inequality(): parent._make_Inequality(self, (c.inhomogeneous_term(),) + c.coefficients()) elif c.is_equality(): parent._make_Equation(self, (c.inhomogeneous_term(),) + c.coefficients()) self._Hrepresentation = tuple(self._Hrepresentation) def _init_empty_polyhedron(self): """ Initializes an empty polyhedron. TESTS:: sage: empty = Polyhedron(backend='ppl'); empty The empty polyhedron in ZZ^0 sage: empty.Vrepresentation() () sage: empty.Hrepresentation() (An equation -1 == 0,) sage: Polyhedron(vertices = [], backend='ppl') The empty polyhedron in ZZ^0 sage: Polyhedron(backend='ppl')._init_empty_polyhedron() """ super(Polyhedron_ppl, self)._init_empty_polyhedron() self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty')
def fibration_generator(self, dim): """ Generate the lattice polytope fibrations. For the purposes of this function, a lattice polytope fiber is a sub-lattice polytope. Projecting the plane spanned by the subpolytope to a point yields another lattice polytope, the base of the fibration. INPUT: - ``dim`` -- integer. The dimension of the lattice polytope fiber. OUTPUT: A generator yielding the distinct lattice polytope fibers of given dimension. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: p = LatticePolytope_PPL((-9,-6,-1,-1),(0,0,0,1),(0,0,1,0),(0,1,0,0),(1,0,0,0)) sage: list( p.fibration_generator(2) ) [A 2-dimensional lattice polytope in ZZ^4 with 3 vertices] """ assert self.is_full_dimensional() # "points" are the potential vertices of the fiber. They are # in the $codim$-skeleton of the polytope, which is contained # in the points that saturate at least $dim$ equations. points = [ p for p in self._integral_points_saturating() if len(p[1])>=dim ] points = sorted(points, key=lambda x:len(x[1])) # iterate over point combinations subject to all points being on one facet. def point_combinations_iterator(n, i0=0, saturated=None): for i in range(i0, len(points)): p, ieqs = points[i] if saturated is None: saturated_ieqs = ieqs else: saturated_ieqs = saturated.intersection(ieqs) if len(saturated_ieqs)==0: continue if n == 1: yield [i] else: for c in point_combinations_iterator(n-1, i+1, saturated_ieqs): yield [i] + c point_lines = [ line(Linear_Expression(p[0].list(),0)) for p in points ] origin = point() fibers = set() gs = Generator_System() for indices in point_combinations_iterator(dim): gs.clear() gs.insert(origin) for i in indices: gs.insert(point_lines[i]) plane = C_Polyhedron(gs) if plane.affine_dimension() != dim: continue plane.intersection_assign(self) if (not self.is_full_dimensional()) and (plane.affine_dimension() != dim): continue try: fiber = LatticePolytope_PPL(plane) except TypeError: # not a lattice polytope continue fiber_vertices = tuple(sorted(fiber.vertices())) if fiber_vertices not in fibers: yield fiber fibers.update([fiber_vertices])
def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of point. Each point can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``rays`` -- list of rays. Each ray can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``lines`` -- list of lines. Each line can be specified as any iterable container of :meth:`~sage.geometry.polyhedron.base.base_ring` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. EXAMPLES:: sage: p = Polyhedron(backend='ppl') sage: from sage.geometry.polyhedron.backend_ppl import Polyhedron_ppl sage: Polyhedron_ppl._init_from_Vrepresentation(p, [], [], []) """ gs = Generator_System() if vertices is None: vertices = [] for v in vertices: d = LCM_list([denominator(v_i) for v_i in v]) if d.is_one(): gs.insert(point(Linear_Expression(v, 0))) else: dv = [d * v_i for v_i in v] gs.insert(point(Linear_Expression(dv, 0), d)) if rays is None: rays = [] for r in rays: d = LCM_list([denominator(r_i) for r_i in r]) if d.is_one(): gs.insert(ray(Linear_Expression(r, 0))) else: dr = [d * r_i for r_i in r] gs.insert(ray(Linear_Expression(dr, 0))) if lines is None: lines = [] for l in lines: d = LCM_list([denominator(l_i) for l_i in l]) if d.is_one(): gs.insert(line(Linear_Expression(l, 0))) else: dl = [d * l_i for l_i in l] gs.insert(line(Linear_Expression(dl, 0))) if gs.empty(): self._ppl_polyhedron = C_Polyhedron(self.ambient_dim(), 'empty') else: self._ppl_polyhedron = C_Polyhedron(gs) self._init_Vrepresentation_from_ppl(minimize) self._init_Hrepresentation_from_ppl(minimize)
def find_isomorphism(self, polytope): r""" Return a lattice isomorphism with ``polytope``. INPUT: - ``polytope`` -- a polytope, potentially higher-dimensional. OUTPUT: A :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticeEuclideanGroupElement`. It is not necessarily invertible if the affine dimension of ``self`` or ``polytope`` is not two. A :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticePolytopesNotIsomorphicError` is raised if no such isomorphism exists. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: L1 = LatticePolytope_PPL((1,0),(0,1),(0,0)) sage: L2 = LatticePolytope_PPL((1,0,3),(0,1,0),(0,0,1)) sage: iso = L1.find_isomorphism(L2) sage: iso(L1) == L2 True sage: L1 = LatticePolytope_PPL((0, 1), (3, 0), (0, 3), (1, 0)) sage: L2 = LatticePolytope_PPL((0,0,2,1),(0,1,2,0),(2,0,0,3),(2,3,0,0)) sage: iso = L1.find_isomorphism(L2) sage: iso(L1) == L2 True The following polygons are isomorphic over `\QQ`, but not as lattice polytopes:: sage: L1 = LatticePolytope_PPL((1,0),(0,1),(-1,-1)) sage: L2 = LatticePolytope_PPL((0, 0), (0, 1), (1, 0)) sage: L1.find_isomorphism(L2) Traceback (most recent call last): ... LatticePolytopesNotIsomorphicError: different number of integral points sage: L2.find_isomorphism(L1) Traceback (most recent call last): ... LatticePolytopesNotIsomorphicError: different number of integral points """ from sage.geometry.polyhedron.lattice_euclidean_group_element import \ LatticePolytopesNotIsomorphicError if polytope.affine_dimension() != self.affine_dimension(): raise LatticePolytopesNotIsomorphicError('different dimension') polytope_vertices = polytope.vertices() if len(polytope_vertices) != self.n_vertices(): raise LatticePolytopesNotIsomorphicError('different number of vertices') self_vertices = self.ordered_vertices() if len(polytope.integral_points()) != len(self.integral_points()): raise LatticePolytopesNotIsomorphicError('different number of integral points') if len(self_vertices) < 3: return self._find_isomorphism_degenerate(polytope) polytope_origin = polytope_vertices[0] origin_P = C_Polyhedron(next(iter(polytope.minimized_generators()))) neighbors = [] for c in polytope.minimized_constraints(): if not c.is_inequality(): continue if origin_P.relation_with(c).implies(Poly_Con_Relation.saturates()): for i, g in enumerate(polytope.minimized_generators()): if i == 0: continue g = C_Polyhedron(g) if g.relation_with(c).implies(Poly_Con_Relation.saturates()): neighbors.append(polytope_vertices[i]) break p_ray_left = neighbors[0] - polytope_origin p_ray_right = neighbors[1] - polytope_origin try: return self._find_cyclic_isomorphism_matching_edge(polytope, polytope_origin, p_ray_left, p_ray_right) except LatticePolytopesNotIsomorphicError: pass try: return self._find_cyclic_isomorphism_matching_edge(polytope, polytope_origin, p_ray_right, p_ray_left) except LatticePolytopesNotIsomorphicError: pass raise LatticePolytopesNotIsomorphicError('different polygons')
def normal_cone(self): r""" Return the (closure of the) normal cone of the triangulation. Recall that a regular triangulation is one that equals the "crease lines" of a convex piecewise-linear function. This support function is not unique, for example, you can scale it by a positive constant. The set of all piecewise-linear functions with fixed creases forms an open cone. This cone can be interpreted as the cone of normal vectors at a point of the secondary polytope, which is why we call it normal cone. See [GKZ1994]_ Section 7.1 for details. OUTPUT: The closure of the normal cone. The `i`-th entry equals the value of the piecewise-linear function at the `i`-th point of the configuration. For an irregular triangulation, the normal cone is empty. In this case, a single point (the origin) is returned. EXAMPLES:: sage: triangulation = polytopes.hypercube(2).triangulate(engine='internal') sage: triangulation (<0,1,3>, <1,2,3>) sage: N = triangulation.normal_cone(); N 4-d cone in 4-d lattice sage: N.rays() ( 0, 0, 0, -1), ( 0, 0, 1, 1), ( 0, 0, -1, -1), ( 1, 0, 0, 1), (-1, 0, 0, -1), ( 0, 1, 0, -1), ( 0, -1, 0, 1) in Ambient free module of rank 4 over the principal ideal domain Integer Ring sage: N.dual().rays() (1, -1, 1, -1) in Ambient free module of rank 4 over the principal ideal domain Integer Ring TESTS:: sage: polytopes.simplex(2).triangulate().normal_cone() 3-d cone in 3-d lattice sage: _.dual().is_trivial() True """ if not self.point_configuration().base_ring().is_subring(QQ): raise NotImplementedError( 'Only base rings ZZ and QQ are supported') from ppl import Constraint_System, Linear_Expression, C_Polyhedron from sage.matrix.constructor import matrix from sage.arith.all import lcm pc = self.point_configuration() cs = Constraint_System() for facet in self.interior_facets(): s0, s1 = self._boundary_simplex_dictionary()[facet] p = set(s0).difference(facet).pop() q = set(s1).difference(facet).pop() origin = pc.point(p).reduced_affine_vector() base_indices = [i for i in s0 if i != p] base = matrix([ pc.point(i).reduced_affine_vector() - origin for i in base_indices ]) sol = base.solve_left(pc.point(q).reduced_affine_vector() - origin) relation = [0] * pc.n_points() relation[p] = sum(sol) - 1 relation[q] = 1 for i, base_i in enumerate(base_indices): relation[base_i] = -sol[i] rel_denom = lcm([QQ(r).denominator() for r in relation]) relation = [ZZ(r * rel_denom) for r in relation] ex = Linear_Expression(relation, 0) cs.insert(ex >= 0) from sage.modules.free_module import FreeModule ambient = FreeModule(ZZ, self.point_configuration().n_points()) if cs.empty(): cone = C_Polyhedron(ambient.dimension(), 'universe') else: cone = C_Polyhedron(cs) from sage.geometry.cone import _Cone_from_PPL return _Cone_from_PPL(cone, lattice=ambient)
class Polytope(object): def __init__(self, halfspaces=None, vertices=None): if halfspaces is not None: self.halfspaces = halfspaces self.dim = halfspaces[0][0].dim self.poly = self.poly_from_constraints(halfspaces) self.vertices = self.vertices_from_poly() elif vertices is not None: v = vertices.pop() self.dim = v.dim vertices.add(v) self.poly = self.poly_from_vertices(vertices) self.vertices = self.vertices_from_poly() self.hyperplanes = self.hyperplanes_from_poly() self.halfspaces = zip(self.hyperplanes, [1] * len(self.hyperplanes)) else: self.hyperplanes = [] self.halfspaces = [] self.vertices = [] self.poly = C_Polyhedron(0) def as_convex_hull(self): vertices = np.array([vertex.coordinates for vertex in self.vertices]) convex_hull = ConvexHull(vertices, qhull_options='Pp') return convex_hull def get_vertex_coordinates(self): return np.array([v.coordinates for v in self.vertices]) def vertices_from_poly(self): # Get vertices of polytope resulting from intersection. only points not rays return np.array([Vertex(pt) for pt in self.poly.minimized_generators() if pt.is_point()]) def poly_from_constraints(self, halfspaces): # Create PPL variables. x = [Variable(i) for i in range(self.dim)] # Init constraint system. constraints = Constraint_System() # Add polytope facets to constraint systems. # Format of ConvexHull.equations: [a1 a2 .. b] => a1*x1 + a2*x2 + .. + b <= 0. for hyp, orient in halfspaces: if orient == -1: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b <= 0) elif orient == 1: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b >= 0) elif orient == 0: constraints.insert(sum(hyp.a[i] * x[i] for i in range(self.dim)) + hyp.b == 0) # Build PPL polyhedra. return C_Polyhedron(constraints) def poly_from_vertices(self, vertices): # Create PPL variables. x = [Variable(i) for i in range(self.dim)] # Init constraint system. generators = Generator_System() # ppl needs coordinates in form of point(sum(a_i *x_i), denom) with a_i integers for vertex in vertices: generators.insert(vertex.ppl) # Build PPL polyhedra. return C_Polyhedron(generators) def hyperplanes_from_poly(self): logging.debug('<nr generators: {}>, <nr constraints: {}>' .format(len(self.poly.generators()), len(self.poly.constraints()))) hyperplanes = [] # constraints in ppl are saved as of the form ax + b >= 0 for constraint in self.poly.minimized_constraints(): a = np.array(constraint.coefficients()) b = constraint.inhomogeneous_term() hyperplane = Hyperplane(a, b) hyperplanes.append(hyperplane) return hyperplanes def add_constraint(self, halfspace): # Create PPL variables. x = [Variable(i) for i in range(self.dim)] if halfspace[1] == -1: self.poly.add_constraint( sum(halfspace[0].a[i] * x[i] for i in range(self.dim)) + halfspace[0].b <= 0) elif halfspace[1] == 1: self.poly.add_constraint( sum(halfspace[0].a[i] * x[i] for i in range(self.dim)) + halfspace[0].b >= 0) elif halfspace[1] == 0: self.poly.add_constraint( sum(halfspace[0].a[i] * x[i] for i in range(self.dim)) + halfspace[0].b == 0) self.hyperplanes = self.hyperplanes_from_poly() self.halfspaces.append(halfspace) self.vertices = self.vertices_from_poly() def point_in_poly(self, point): return self.poly.relation_with(point.ppl).implies(Poly_Gen_Relation.subsumes())