Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
    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)
Esempio n. 5
0
    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
Esempio n. 6
0
    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
Esempio n. 7
0
    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)
Esempio n. 8
0
    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')
Esempio n. 9
0
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())
Esempio n. 10
0
    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')