Exemplo n.º 1
0
    def find_isomorphism(self, polytope):
        """
        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(Generator_System_iterator(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')
Exemplo n.º 2
0
def LatticePolytope_PPL(*args):
    """
    Construct a new instance of the PPL-based lattice polytope class.

    EXAMPLES::

        sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
        sage: LatticePolytope_PPL((0,0),(1,0),(0,1))
        A 2-dimensional lattice polytope in ZZ^2 with 3 vertices

        sage: from sage.libs.ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable
        sage: p = point(Linear_Expression([2,3],0));  p
        point(2/1, 3/1)
        sage: LatticePolytope_PPL(p)
        A 0-dimensional lattice polytope in ZZ^2 with 1 vertex

        sage: P = C_Polyhedron(Generator_System(p));  P
        A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point
        sage: LatticePolytope_PPL(P)
        A 0-dimensional lattice polytope in ZZ^2 with 1 vertex

    A ``TypeError`` is raised if the arguments do not specify a lattice polytope::

        sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
        sage: LatticePolytope_PPL((0,0),(1/2,1))
        Traceback (most recent call last):
        ...
        TypeError: no conversion of this rational to integer

        sage: from sage.libs.ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable
        sage: p = point(Linear_Expression([2,3],0), 5);  p
        point(2/5, 3/5)
        sage: LatticePolytope_PPL(p)
        Traceback (most recent call last):
         ...
        TypeError: generator is not a lattice polytope generator

        sage: P = C_Polyhedron(Generator_System(p));  P
        A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point
        sage: LatticePolytope_PPL(P)
        Traceback (most recent call last):
        ...
        TypeError: polyhedron has non-integral generators
    """
    polytope_class = LatticePolytope_PPL_class
    if len(args)==1 and isinstance(args[0], C_Polyhedron):
        polyhedron = args[0]
        polytope_class = _class_for_LatticePolytope(polyhedron.space_dimension())
        if not all(p.is_point() and p.divisor().is_one() for p in polyhedron.generators()):
            raise TypeError('polyhedron has non-integral generators')
        return polytope_class(polyhedron)
    if len(args)==1 \
            and isinstance(args[0], (list, tuple)) \
            and isinstance(args[0][0], (list,tuple)):
        vertices = args[0]
    else:
        vertices = args
    gs = Generator_System()
    for v in vertices:
        if isinstance(v, Generator):
            if (not v.is_point()) or (not v.divisor().is_one()):
                raise TypeError('generator is not a lattice polytope generator')
            gs.insert(v)
        else:
            gs.insert(point(Linear_Expression(v, 0)))
    if not gs.empty():
        dim = Generator_System_iterator(gs).next().space_dimension()
        polytope_class = _class_for_LatticePolytope(dim)
    return polytope_class(gs)