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')
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)