# Ticket #12544: trac_12544_switch_cones_to_PointCollection_folded.patch

File trac_12544_switch_cones_to_PointCollection_folded.patch, 118.0 KB (added by novoselt, 9 years ago)
• ## sage/geometry/cone.py

# HG changeset patch
# User Andrey Novoseltsev <novoselt@gmail.com>
# Date 1331053635 25200
Switch cones to using PointCollection for ray generators instead of tuples.
* * *
Adjust doctests to new cone.rays() output.
* * *
Add deprecation warnings to old-style ray handling methods, stop using them.
* * *
Transpose the matrix of PointCollection to make matrix(pc)==pc.matrix().

diff --git a/sage/geometry/cone.py b/sage/geometry/cone.py
 a - Volker Braun (2010-12-28): Hilbert basis for cones. - Andrey Novoseltsev (2012-02-23): switch to PointCollection container. EXAMPLES: Use :func:Cone to construct cones:: Once you have a cone, you can perform numerous operations on it. The most important ones are, probably, ray accessing methods:: sage: halfspace.rays() (N(0, 0, 1), N(0, 1, 0), N(0, -1, 0), N(1, 0, 0), N(-1, 0, 0)) sage: rays = halfspace.rays() sage: rays N( 0,  0, 1), N( 0,  1, 0), N( 0, -1, 0), N( 1,  0, 0), N(-1,  0, 0) in 3-d lattice N sage: rays.set() frozenset([N(1, 0, 0), N(-1, 0, 0), N(0, 1, 0), N(0, 0, 1), N(0, -1, 0)]) sage: rays.matrix() [ 0  0  1] [ 0  1  0] [ 0 -1  0] [ 1  0  0] [-1  0  0] sage: rays.column_matrix() [ 0  0  0  1 -1] [ 0  1 -1  0  0] [ 1  0  0  0  0] sage: rays(3) N(1, 0, 0) in 3-d lattice N sage: rays[3] N(1, 0, 0) sage: halfspace.ray(3) N(1, 0, 0) sage: halfspace.ray_matrix() [ 0  0  0  1 -1] [ 0  1 -1  0  0] [ 1  0  0  0  0] sage: halfspace.ray_set() frozenset([N(1, 0, 0), N(-1, 0, 0), N(0, 1, 0), N(0, 0, 1), N(0, -1, 0)]) The method :meth:~ConvexRationalPolyhedralCone.rays returns a :class:~sage.geometry.point_collection.PointCollection with the i-th element being the primitive integral generator of the i-th ray. It is possible to convert this collection to a matrix with either rows or columns corresponding to these generators. You may also change the default meth:~sage.geometry.point_collection.PointCollection.output_format of all point collections such a matrix. If you want to do something with each ray of a cone, you can write :: N(1, 0, 0) N(0, 1, 0) You can also get an iterator over only some selected rays:: sage: for ray in halfspace.ray_iterator([1,2,1]): print ray N(0, 1, 0) N(0, -1, 0) N(0, 1, 0) There are two dimensions associated to each cone - the dimension of the subspace spanned by the cone and the dimension of the space where it lives:: sage: face 2-d face of 3-d cone in 3-d lattice N sage: face.rays() (N(1, 1, 1), N(1, -1, 1)) N(1,  1, 1), N(1, -1, 1) in 3-d lattice N sage: face.ambient_ray_indices() (0, 1) sage: four_rays.rays(face.ambient_ray_indices()) (N(1, 1, 1), N(1, -1, 1)) N(1,  1, 1), N(1, -1, 1) in 3-d lattice N If you need to know inclusion relations between faces, you can use :: [1, 4, 4, 1] sage: face = L.level_sets()[2][0] sage: face.element.rays() (N(1, 1, 1), N(1, -1, 1)) N(1,  1, 1), N(1, -1, 1) in 3-d lattice N sage: L.hasse_diagram().neighbors_in(face) [1-d face of 3-d cone in 3-d lattice N, 1-d face of 3-d cone in 3-d lattice N] .. WARNING:: As you can see in the above example, the order of faces in level sets of The order of faces in level sets of the face lattice may differ from the order of faces returned by :meth:~ConvexRationalPolyhedralCone.faces. While the first order is random, the latter one ensures that one-dimensional faces are listed in #***************************************************************************** #       Copyright (C) 2010 Volker Braun #       Copyright (C) 2010 Andrey Novoseltsev #       Copyright (C) 2012 Andrey Novoseltsev #       Copyright (C) 2010 William Stein # # #  Distributed under the terms of the GNU General Public License (GPL) # #  as published by the Free Software Foundation; either version 2 of #  the License, or (at your option) any later version. #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.combinat.posets.posets import FinitePoset from sage.geometry.lattice_polytope import LatticePolytope, integral_length from sage.geometry.point_collection import PointCollection from sage.geometry.polyhedron.constructor import Polyhedron from sage.geometry.polyhedron.base import is_Polyhedron from sage.geometry.hasse_diagram import Hasse_diagram_from_incidences from sage.geometry.toric_plotter import ToricPlotter, label_list from sage.graphs.all import DiGraph from sage.matrix.all import matrix, identity_matrix from sage.misc.all import flatten, latex, prod from sage.misc.all import cached_method, flatten, latex, prod from sage.misc.misc import deprecation from sage.modules.all import span, vector from sage.rings.all import QQ, RR, ZZ, gcd from sage.structure.all import SageObject sage: quadrant 2-d cone in 2-d lattice N sage: quadrant.rays() (N(1, 0), N(0, 1)) You may prefer to use :meth:~IntegralRayCollection.ray_matrix when you want to take a look at rays, they will be given as columns:: sage: quadrant.ray_matrix() [1 0] [0 1] N(1, 0), N(0, 1) in 2-d lattice N If you give more rays than necessary, the extra ones will be discarded:: sage: Cone([(1,0), (0,1), (1,1), (0,1)]).rays() (N(0, 1), N(1, 0)) N(0, 1), N(1, 0) in 2-d lattice N However, this work is not done with check=False option, so use it carefully! :: sage: Cone([(1,0), (0,1), (1,1), (0,1)], check=False).rays() (N(1, 0), N(0, 1), N(1, 1), N(0, 1)) N(1, 0), N(0, 1), N(1, 1), N(0, 1) in 2-d lattice N Even worse things can happen with normalize=False option:: 1 sage: half_plane = Cone([(1,0), (0,1), (-1,0)]) sage: half_plane.rays() (N(0, 1), N(1, 0), N(-1, 0)) N( 0, 1), N( 1, 0), N(-1, 0) in 2-d lattice N sage: half_plane.is_strictly_convex() False sage: origin = Cone([(0,0)]) sage: origin.rays() () Empty collection in 2-d lattice N sage: origin.dim() 0 sage: origin.lattice_dim() 2 You may construct the cone above without giving any rays, but in this case you must provide lattice explicitly:: you must provide lattice explicitly:: sage: origin = Cone([]) Traceback (most recent call last): sage: origin.lattice() 2-d lattice N Of course, you can also provide lattice in other cases:: Of course, you can also provide lattice in other cases:: sage: L = ToricLattice(3, "L") sage: c1 = Cone([(1,0,0),(1,1,1)], lattice=L) sage: c1.rays() (L(1, 0, 0), L(1, 1, 1)) L(1, 0, 0), L(1, 1, 1) in 3-d lattice L Or you can construct cones from rays of a particular lattice:: sage: ray2 = L(1,1,1) sage: c2 = Cone([ray1, ray2]) sage: c2.rays() (L(1, 0, 0), L(1, 1, 1)) L(1, 0, 0), L(1, 1, 1) in 3-d lattice L sage: c1 == c2 True negatives", as in the following example:: sage: plane = Cone([(1,0), (0,1), (-1,-1)]) sage: plane.ray_matrix() [ 0  0  1 -1] [ 1 -1  0  0] sage: plane.rays() N( 0,  1), N( 0, -1), N( 1,  0), N(-1,  0) in 2-d lattice N The cone can also be specified by a :class:~sage.geometry.polyhedron.base.Polyhedron_base:: raise ValueError("the apex of %s is not at the origin!" % polyhedron) rays = normalize_rays(polyhedron.rays(), lattice) strict_rays = tuple(rays) lines = tuple(normalize_rays(polyhedron.lines(), lattice)) for line in lines: for line in normalize_rays(polyhedron.lines(), lattice): rays.append(line) rays.append(-line) rays[-1].set_immutable() cone = ConvexRationalPolyhedralCone(rays, lattice) # Save constructed stuff for later use cone._polyhedron = polyhedron cone._strict_rays = strict_rays cone._lines = lines return cone return ConvexRationalPolyhedralCone(rays, lattice) # Cone from rays if check or normalize: rays = normalize_rays(rays, lattice) TESTS:: sage: Cone([(1,0), (0,1), (1,1), (0,1)]).rays()   # indirect doctest (N(0, 1), N(1, 0)) N(0, 1), N(1, 0) in 2-d lattice N """ rays = [] lines = [] Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: c.rays() ((1, 0),) (1, 0) in Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: TestSuite(c).run() """ self._rays = tuple(rays) self._rays = PointCollection(rays, lattice) self._lattice = self._rays[0].parent() if lattice is None else lattice def __cmp__(self, right): N(1, 0) N(0, 1) """ return self.ray_iterator() return iter(self._rays) def _ambient_space_point(self, data): r""" sage: c.cartesian_product(c)    # indirect doctest 2-d cone in 2-d lattice N+N sage: _.rays() (N+N(1, 0), N+N(0, 1)) N+N(1, 0), N+N(0, 1) in 2-d lattice N+N """ assert isinstance(other, IntegralRayCollection) if lattice is None: 1 """ if "_dim" not in self.__dict__: self._dim = self.ray_matrix().rank() self._dim = self.rays().matrix().rank() return self._dim def lattice(self): EXAMPLES:: sage: c = Cone([(1,0), (0,1), (-1, 0)]) sage: for ray in c.ray_iterator(): print ray N(0, 1) N(1, 0) N(-1, 0) sage: for ray in c.ray_iterator([2,1]): print ray N(-1, 0) N(1, 0) sage: [ray for ray in c.ray_iterator()] doctest:...: DeprecationWarning: (Since Sage Version 5.1) ray_iterator(...) is deprecated! [N(0, 1), N(1, 0), N(-1, 0)] """ # I couldn't move it to the new Cython class due to some issues with # generators (may be resolved in 0.16). However, this particular # iterator does not really save time or memory, so I think it can just # go. -- Andrey Novoseltsev, 2012-03-06. deprecation("ray_iterator(...) is deprecated!", "Sage Version 5.1") if ray_list is None: for ray in self._rays: yield ray sage: c = Cone([(1,0), (0,1), (-1, 0)]) sage: c.ray_matrix() doctest:...: DeprecationWarning: (Since Sage Version 5.1) ray_matrix(...) is deprecated, please use rays().column_matrix() instead! [ 0  1 -1] [ 1  0  0] """ if "_ray_matrix" not in self.__dict__: self._ray_matrix = matrix(ZZ, self.nrays(), self.lattice().degree(), self._rays).transpose() self._ray_matrix.set_immutable() return self._ray_matrix deprecation("ray_matrix(...) is deprecated, " "please use rays().column_matrix() instead!", "Sage Version 5.1") return self.rays().column_matrix() def ray_set(self): r""" sage: c = Cone([(1,0), (0,1), (-1, 0)]) sage: c.ray_set() doctest:1: DeprecationWarning: (Since Sage Version 5.1) ray_set(...) is deprecated, please use rays().set() instead! frozenset([N(0, 1), N(1, 0), N(-1, 0)]) """ if "_ray_set" not in self.__dict__: self._ray_set = frozenset(self._rays) return self._ray_set def rays(self, ray_list=None): deprecation("ray_set(...) is deprecated, " "please use rays().set() instead!", "Sage Version 5.1") return self.rays().set() def rays(self, *args): r""" Return rays of self as a :class:tuple. Return (some of the) rays of self. INPUT: - ray_list -- list of integers, the indices of the requested rays. If not specified, all rays of self will be returned. You may want to use :meth:ray_set if you do not care about the order of rays. See also :meth:ray_iterator. - ray_list -- a list of integers, the indices of the requested rays. If not specified, all rays of self will be returned. OUTPUT: - :class:tuple of rays. - a :class:PointCollection of primitive integral ray generators. EXAMPLES:: sage: c = Cone([(1,0), (0,1), (-1, 0)]) sage: c.rays() (N(0, 1), N(1, 0), N(-1, 0)) N( 0, 1), N( 1, 0), N(-1, 0) in 2-d lattice N sage: c.rays([0, 2]) (N(0, 1), N(-1, 0)) N( 0, 1), N(-1, 0) in 2-d lattice N You can also give ray indices directly, without packing them into a list:: sage: c.rays(0, 2) N( 0, 1), N(-1, 0) in 2-d lattice N """ if ray_list is None: return self._rays else: return tuple(self.ray_iterator(ray_list)) return self._rays if not args else self._rays(*args) def ray_basis(self): r""" sage: c = Cone([(1,1,1,1), (1,-1,1,1), (-1,-1,1,1), (-1,1,1,1), (0,0,0,1)]) sage: c.ray_basis() (N(1, 1, 1, 1), N(1, -1, 1, 1), N(-1, -1, 1, 1), N(0, 0, 0, 1)) doctest:...: DeprecationWarning: (Since Sage Version 5.1) ray_basis(...) is deprecated, please use rays().basis() instead! N( 1,  1, 1, 1), N( 1, -1, 1, 1), N(-1, -1, 1, 1), N( 0,  0, 0, 1) in 4-d lattice N """ if "_ray_basis" not in self.__dict__: indices = self.ray_matrix().pivots() self._ray_basis = tuple(self.ray(i) for i in indices) return self._ray_basis deprecation("ray_basis(...) is deprecated, " "please use rays().basis() instead!", "Sage Version 5.1") return self.rays().basis() def ray_basis_matrix(self): r""" sage: c = Cone([(1,1,1,1), (1,-1,1,1), (-1,-1,1,1), (-1,1,1,1), (0,0,0,1)]) sage: c.ray_basis_matrix() doctest:...: DeprecationWarning: (Since Sage Version 5.1) ray_basis_matrix(...) is deprecated, please use rays().basis().column_matrix() instead! [ 1  1 -1  0] [ 1 -1 -1  0] [ 1  1  1  0] [ 1  1  1  1] """ basis = self.ray_basis() m = self._lattice.degree() n = len(basis) return matrix(ZZ, n, m, basis).transpose() deprecation("ray_basis_matrix(...) is deprecated, " "please use rays().basis().column_matrix() instead!", "Sage Version 5.1") return self.rays().basis().column_matrix() # Derived classes MUST allow construction of their objects using ambient Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: ac.rays() ((1, 0), (0, 1)) (1, 0), (0, 1) in Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: ac.ambient() is ac True sage: TestSuite(ac).run() sage: sc = ConvexRationalPolyhedralCone(ambient=ac, ...                         ambient_ray_indices=[1]) sage: sc.rays() ((0, 1),) (0, 1) in Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: sc.ambient() is ac True sage: TestSuite(sc).run() sage: c.cartesian_product(c) 2-d cone in 2-d lattice N+N sage: _.rays() (N+N(1, 0), N+N(0, 1)) N+N(1, 0), N+N(0, 1) in 2-d lattice N+N """ assert is_Cone(other) rc = super(ConvexRationalPolyhedralCone, self).cartesian_product( key=lambda f: f._ambient_ray_indices)) return faces @cached_method def adjacent(self): r""" Return faces adjacent to self in the ambient face lattice. adjacent cones must be facets of a bigger one, but since cone in this example is generating, it is not contained in any other. """ if "_adjacent" not in self.__dict__: L = self._ambient._face_lattice_function() adjacent = set() facets = self.facets() superfaces = self.facet_of() if superfaces: for superface in superfaces: for facet in facets: adjacent.update(L.open_interval(facet,  superface)) if adjacent: adjacent.remove(L(self)) self._adjacent = self._sort_faces(face.element for face in adjacent) elif self.dim() == self._ambient.dim(): # Special treatment relevant for fans L = self._ambient._face_lattice_function() adjacent = set() facets = self.facets() superfaces = self.facet_of() if superfaces: for superface in superfaces: for facet in facets: adjacent.update(facet.facet_of()) if adjacent: adjacent.remove(self) self._adjacent = self._sort_faces(adjacent) else: self._adjacent = () return self._adjacent adjacent.update(L.open_interval(facet,  superface)) if adjacent: adjacent.remove(L(self)) return self._sort_faces(face.element for face in adjacent) elif self.dim() == self._ambient.dim(): # Special treatment relevant for fans for facet in facets: adjacent.update(facet.facet_of()) if adjacent: adjacent.remove(self) return self._sort_faces(adjacent) else: return () def ambient(self): r""" sage: cone = Cone([(1,0), (-1,3)]) sage: cone.dual().rays() (M(3, 1), M(0, 1)) M(3, 1), M(0, 1) in 2-d lattice M Now let's look at a more complicated case:: sage: cone.dim() 3 sage: cone.dual().rays() (M(7, -18, -2), M(1, -4, 0)) M(7, -18, -2), M(1,  -4,  0) in 3-d lattice M sage: cone.dual().dual() is cone True sage: N = ToricLattice(2) sage: Cone([], lattice=N).dual().rays()  # empty cone (M(1, 0), M(-1, 0), M(0, 1), M(0, -1)) M( 1,  0), M(-1,  0), M( 0,  1), M( 0, -1) in 2-d lattice M sage: Cone([(1,0)], lattice=N).dual().rays()  # ray in 2d (M(1, 0), M(0, 1), M(0, -1)) M(1,  0), M(0,  1), M(0, -1) in 2-d lattice M sage: Cone([(1,0),(-1,0)], lattice=N).dual().rays()  # line in 2d (M(0, 1), M(0, -1)) M(0,  1), M(0, -1) in 2-d lattice M sage: Cone([(1,0),(0,1)], lattice=N).dual().rays()  # strictly convex cone (M(1, 0), M(0, 1)) M(1, 0), M(0, 1) in 2-d lattice M sage: Cone([(1,0),(-1,0),(0,1)], lattice=N).dual().rays()  # half space (M(0, 1),) M(0, 1) in 2-d lattice M sage: Cone([(1,0),(0,1),(-1,-1)], lattice=N).dual().rays()  # whole space () Empty collection in 2-d lattice M """ if "_dual" not in self.__dict__: rays = list(self.facet_normals()) sage: e_ray 1-d face of 3-d cone in 3-d lattice N sage: e_ray.rays() (N(0, -1, 1),) N(0, -1, 1) in 3-d lattice N sage: e_ray is ray False sage: e_ray.is_equivalent(ray) sage: face.rays() Traceback (most recent call last): ... AttributeError: 'FinitePoset_with_category.element_class' object has no attribute 'rays' AttributeError: 'FinitePoset_with_category.element_class' object has no attribute 'rays' To get the actual face you need one more step:: Now you can look at the actual rays of this face... :: sage: face.rays() (N(1, 0),) N(1, 0) in 2-d lattice N ... or you can see indices of the rays of the orginal cone that correspond to the above ray:: sage: face 1-d face of 2-d cone in 2-d lattice N sage: face.rays() (N(1, 0),) N(1, 0) in 2-d lattice N sage: face.facets() (0-d face of 2-d cone in 2-d lattice N,) sage: face.facet_of() sage: face.adjacent() (1-d face of 2-d cone in 2-d lattice N,) sage: face.adjacent()[0].rays() (N(0, 1),) N(0, 1) in 2-d lattice N Note that if cone is a face of supercone, then the face lattice of cone consists of (appropriate) faces of supercone:: Now you can look at the actual rays of this face... :: sage: face.rays() (N(1, 0),) N(1, 0) in 2-d lattice N ... or you can see indices of the rays of the orginal cone that correspond to the above ray:: (3-d cone in 4-d lattice N,)) We also ensure that a call to this function does not break :meth:facets method (see Trac #9780):: :meth:facets method (see :trac:9780):: sage: cone = toric_varieties.dP8().fan().generating_cone(0) sage: cone 2-d cone of Rational polyhedral fan in 2-d lattice N sage: [f.rays() for f in cone.facets()] [(N(1, 1),), (N(0, 1),)] sage: for f in cone.facets(): print f.rays() N(1, 1) in 2-d lattice N N(0, 1) in 2-d lattice N sage: len(cone.faces()) 3 sage: [f.rays() for f in cone.facets()] [(N(1, 1),), (N(0, 1),)] sage: for f in cone.facets(): print f.rays() N(1, 1) in 2-d lattice N N(0, 1) in 2-d lattice N """ if dim is not None and codim is not None: raise ValueError( OUTPUT: - :class:tuple of vectors. - a :class:PointCollection. If the ambient :meth:~IntegralRayCollection.lattice of self is a :class:toric lattice sage: cone = Cone([(1,0), (-1,3)]) sage: cone.facet_normals() (M(3, 1), M(0, 1)) M(3, 1), M(0, 1) in 2-d lattice M Now let's look at a more complicated case:: sage: lsg = (QQ^3)(cone.linear_subspace().gen(0)); lsg (1, 1/4, 5/4) sage: cone.facet_normals() (M(7, -18, -2), M(1, -4, 0)) M(7, -18, -2), M(1,  -4,  0) in 3-d lattice M sage: [lsg*normal for normal in cone.facet_normals()] [0, 0] A lattice that does not have a dual() method:: sage: Cone([(1,1),(0,1)], lattice=ZZ^2).facet_normals() ((1, 0), (-1, 1)) ( 1, 0), (-1, 1) in Ambient free module of rank 2 over the principal ideal domain Integer Ring We correctly handle the degenerate cases:: sage: N = ToricLattice(2) sage: Cone([], lattice=N).facet_normals()  # empty cone () Empty collection in 2-d lattice M sage: Cone([(1,0)], lattice=N).facet_normals()  # ray in 2d (M(1, 0),) M(1, 0) in 2-d lattice M sage: Cone([(1,0),(-1,0)], lattice=N).facet_normals()  # line in 2d () Empty collection in 2-d lattice M sage: Cone([(1,0),(0,1)], lattice=N).facet_normals()  # strictly convex cone (M(1, 0), M(0, 1)) M(1, 0), M(0, 1) in 2-d lattice M sage: Cone([(1,0),(-1,0),(0,1)], lattice=N).facet_normals()  # half space (M(0, 1),) M(0, 1) in 2-d lattice M sage: Cone([(1,0),(0,1),(-1,-1)], lattice=N).facet_normals()  # whole space () Empty collection in 2-d lattice M """ if "_facet_normals" not in self.__dict__: cone = self._PPL_cone() if c.is_inequality(): normals.append(c.coefficients()) M = self.dual_lattice() normals = tuple(map(M,normals)) normals = tuple(map(M, normals)) for n in normals: n.set_immutable() self._facet_normals = normals self._facet_normals = PointCollection(normals, M) return self._facet_normals def facet_of(self): sage: cone1 = Cone([(1,0), (-1, 3)]) sage: cone2 = Cone([(-1,0), (2, 5)]) sage: cone1.intersection(cone2).rays() (N(-1, 3), N(2, 5)) N(-1, 3), N( 2, 5) in 2-d lattice N It is OK to intersect cones living in sublattices of the same ambient lattice:: sage: cone3 = Cone([(1,1)], lattice=Ns) sage: I = cone1.intersection(cone3) sage: I.rays() (N(1, 1),) N(1, 1) in Sublattice sage: I.lattice() Sublattice ValueError: 2-d lattice N and 2-d lattice M have different ambient lattices! sage: cone1.intersection(Cone(cone1.dual().rays(), N)).rays() (N(3, 1), N(0, 1)) N(3, 1), N(0, 1) in 2-d lattice N """ if self._ambient is other._ambient: # Cones of the same ambient cone or fan intersect nicely/quickly. sage: cone1 = Cone([(1,0), (-1, 3)]) sage: cone2 = Cone([(-1,3), (1, 0)]) sage: cone1.rays() (N(1, 0), N(-1, 3)) N( 1, 0), N(-1, 3) in 2-d lattice N sage: cone2.rays() (N(-1, 3), N(1, 0)) N(-1, 3), N( 1, 0) in 2-d lattice N sage: cone1 == cone2 False sage: cone1.is_equivalent(cone2) return False if self._ambient is cone._ambient: # Cones are always faces of their ambient structure, so return self.ray_set().issubset(cone.ray_set()) return self.rays().set().issubset(cone.rays().set()) if self.is_equivalent(cone): return True # Obviously False case """ return self.nrays() == self.dim() @cached_method def is_smooth(self): r""" Check if self is smooth. sage: Cone([(1,0,0), (2,1,2)]).is_smooth() True """ if "_is_smooth" not in self.__dict__: if not self.is_simplicial(): self._is_smooth = False else: elementary_divisors = self.ray_matrix().transpose().elementary_divisors() self._is_smooth = (elementary_divisors == [1]*self.nrays()) return self._is_smooth if not self.is_simplicial(): return False return self.rays().matrix().elementary_divisors() == [1] * self.nrays() def is_trivial(self): """ [ 0  0] """ if "_lattice_polytope" not in self.__dict__: m = self.ray_matrix() if self.is_strictly_convex(): m = m.augment(matrix(ZZ, self.lattice().degree(), 1)) # origin self._lattice_polytope = LatticePolytope(m, compute_vertices=False, copy_vertices=False) self._lattice_polytope = LatticePolytope( tuple(self.rays()) + (self.lattice().zero(),), compute_vertices=not self.is_strictly_convex()) return self._lattice_polytope def line_set(self): sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.line_set() doctest:1: DeprecationWarning: (Since Sage Version 5.1) line_set(...) is deprecated, please use lines().set() instead! frozenset([N(1, 0)]) sage: fullplane = Cone([(1,0), (0,1), (-1,-1)]) sage: fullplane.line_set() frozenset([N(0, 1), N(1, 0)]) """ deprecation("line_set(...) is deprecated, " "please use lines().set() instead!", "Sage Version 5.1") if "_line_set" not in self.__dict__: self._line_set = frozenset(self.lines()) return self._line_set @cached_method def linear_subspace(self): r""" Return the largest linear subspace contained inside of self. Basis matrix: [1 0] """ if "_linear_subspace" not in self.__dict__: if self.is_strictly_convex(): self._linear_subspace = span( [vector(QQ, self.lattice_dim())], QQ) else: self._linear_subspace = span(self.lines(), QQ) return self._linear_subspace if self.is_strictly_convex(): return span([vector(QQ, self.lattice_dim())], QQ) return span(self.lines(), QQ) @cached_method def lines(self): r""" Return lines generating the linear subspace of self. sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.lines() (N(1, 0),) N(1, 0) in 2-d lattice N sage: fullplane = Cone([(1,0), (0,1), (-1,-1)]) sage: fullplane.lines() (N(0, 1), N(1, 0)) N(0, 1), N(1, 0) in 2-d lattice N """ if "_lines" not in self.__dict__: lines = [] for g in self._PPL_cone().minimized_generators(): if g.is_line(): lines.append(g.coefficients()) N = self.lattice() lines = tuple(map(N,lines)) for l in lines: l.set_immutable() self._lines = lines return self._lines lines = [] for g in self._PPL_cone().minimized_generators(): if g.is_line(): lines.append(g.coefficients()) N = self.lattice() lines = tuple(map(N, lines)) for l in lines: l.set_immutable() return PointCollection(lines, N) def plot(self, **options): r""" sage: ssc 1-d cone in 1-d lattice N sage: ssc.rays() (N(1),) N(1) in 1-d lattice N sage: line = Cone([(1,0), (-1,0)]) sage: ssc = line.strict_quotient() sage: ssc 0-d cone in 1-d lattice N sage: ssc.rays() () Empty collection in 1-d lattice N """ if "_strict_quotient" not in self.__dict__: if self.is_strictly_convex(): sage: trivial_cone._orthogonal_sublattice_complement Sublattice <> """ Nsigma = self.ray_basis_matrix() Nsigma = self.rays().basis().matrix().transpose() r = Nsigma.ncols() D, U, V = Nsigma.smith_form()  # D = U*N*V <=> N = Uinv*D*Vinv Uinv = U.inverse() EXAMPLES:: sage: cone = Cone([(1, 1, 1), (1, -1, 1), (-1, -1, 1), (-1, 1, 1)]) sage: cone.ray_basis_matrix() [ 1  1 -1] [ 1 -1 -1] [ 1  1  1] sage: cone.ray_basis_matrix().det() sage: cone.rays().basis() N( 1,  1, 1), N( 1, -1, 1), N(-1, -1, 1) in 3-d lattice N sage: cone.rays().basis().matrix().det() -4 sage: cone.sublattice() Sublattice sage: c 2-d cone in 3-d lattice N sage: c.rays() (N(1, 2, 3), N(4, -5, 1)) N(1,  2, 3), N(4, -5, 1) in 3-d lattice N sage: c.sublattice() Sublattice sage: c.sublattice(5, -3, 4) extra_ray = None if Ncone.dimension()-Nsubcone.dimension()==1: extra_ray = set(self.ray_set() - subcone.ray_set()).pop() extra_ray = set(self.rays().set() - subcone.rays().set()).pop() Q = Ncone.quotient(Nsubcone, positive_point=extra_ray) assert Q.is_torsion_free() extra_ray = None if Mcone.dimension()-Msupercone.dimension()==1: extra_ray = set(supercone.ray_set() - self.ray_set()).pop() extra_ray = set(supercone.rays().set() - self.rays().set()).pop() Q = Mcone.quotient(Msupercone, positive_dual_point=extra_ray) assert Q.is_torsion_free() OUTPUT: A tuple of lattice points generating the semigroup of lattice points contained in this cone. - a :class:PointCollection of lattice points generating the semigroup of lattice points contained in self. .. note:: No attempt is made to return a minimal set of generators, see :meth:Hilbert_basis for that. We start with a simple case of a non-smooth 2-dimensional cone:: sage: Cone([ (1,0), (1,2) ]).semigroup_generators() (N(1, 1), N(1, 0), N(1, 2)) N(1, 1), N(1, 0), N(1, 2) in 2-d lattice N A non-simplicial cone works, too:: http://trac.sagemath.org/sage_trac/ticket/11312):: sage: Cone([(1,1,0), (-1,1,0)]).semigroup_generators() (N(0, 1, 0), N(1, 1, 0), N(-1, 1, 0)) N( 0, 1, 0), N( 1, 1, 0), N(-1, 1, 0) in 3-d lattice N Neither full-dimensional nor simplicial:: sage: trivial_cone = Cone([], lattice=ToricLattice(3)) sage: trivial_cone.semigroup_generators() () Empty collection in 3-d lattice N ALGORITHM: # recursively N = self.lattice() if not self.is_simplicial(): from sage.geometry.triangulation.point_configuration import PointConfiguration from sage.geometry.triangulation.point_configuration \ import PointConfiguration origin = self.nrays() # last one in pc pc = PointConfiguration(self.rays() + (N(0),), star=origin) pc = PointConfiguration(tuple(self.rays()) + (N(0),), star=origin) triangulation = pc.triangulate() subcones = [ Cone([self.ray(i) for i in simplex if i!=origin], lattice=N, check=False) return tuple(gens) gens = list(parallelotope_points(self.rays(), N)) + list(self.rays()) gens = filter(lambda v:gcd(v)==1, gens) return tuple(gens) gens = filter(lambda v: gcd(v) == 1, gens) return PointCollection(gens, N) @cached_method def Hilbert_basis(self): r""" Return the Hilbert basis of the cone. OUTPUT: A tuple of lattice points. The rays of the cone are the first self.nrays() entries. - a :class:PointCollection. The rays of self are the first self.nrays() entries. EXAMPLES: We start with a simple case of a non-smooth 2-dimensional cone:: sage: Cone([ (1,0), (1,2) ]).Hilbert_basis() (N(1, 0), N(1, 2), N(1, 1)) N(1, 0), N(1, 2), N(1, 1) in 2-d lattice N Two more complicated example from GAP/toric:: sage: Cone([[1,0],[3,4]]).dual().Hilbert_basis() (M(0, 1), M(4, -3), M(3, -2), M(2, -1), M(1, 0)) M(0,  1), M(4, -3), M(3, -2), M(2, -1), M(1,  0) in 2-d lattice M sage: cone = Cone([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]).dual() sage: cone.Hilbert_basis()           # long time (M(10, -7, 0, 1), M(-5, 21, 0, -3), M(0, -2, 0, 1), M(15, -63, 25, 9), M(2, -3, 0, 1), M(1, -4, 1, 1), M(-1, 3, 0, 0), M(4, -4, 0, 1), M(1, -5, 2, 1), M(3, -5, 1, 1), M(6, -5, 0, 1), M(3, -13, 5, 2), M(2, -6, 2, 1), M(5, -6, 1, 1), M(0, 1, 0, 0), M(8, -6, 0, 1), M(-2, 8, 0, -1), M(10, -42, 17, 6), M(7, -28, 11, 4), M(5, -21, 9, 3), M(6, -21, 8, 3), M(5, -14, 5, 2), M(2, -7, 3, 1), M(4, -7, 2, 1), M(7, -7, 1, 1), M(0, 0, 1, 0), M(-3, 14, 0, -2), M(-1, 7, 0, -1), M(1, 0, 0, 0)) M(10,  -7,  0,  1), M(-5,  21,  0, -3), M( 0,  -2,  0,  1), M(15, -63, 25,  9), M( 2,  -3,  0,  1), M( 1,  -4,  1,  1), M(-1,   3,  0,  0), M( 4,  -4,  0,  1), M( 1,  -5,  2,  1), M( 3,  -5,  1,  1), M( 6,  -5,  0,  1), M( 3, -13,  5,  2), M( 2,  -6,  2,  1), M( 5,  -6,  1,  1), M( 0,   1,  0,  0), M( 8,  -6,  0,  1), M(-2,   8,  0, -1), M(10, -42, 17,  6), M( 7, -28, 11,  4), M( 5, -21,  9,  3), M( 6, -21,  8,  3), M( 5, -14,  5,  2), M( 2,  -7,  3,  1), M( 4,  -7,  2,  1), M( 7,  -7,  1,  1), M( 0,   0,  1,  0), M(-3,  14,  0, -2), M(-1,   7,  0, -1), M( 1,   0,  0,  0) in 4-d lattice M Not a strictly convex cone:: sage: wedge.semigroup_generators() (N(1, 0, 0), N(1, 1, 0), N(1, 2, 0), N(0, 0, 1), N(0, 0, -1)) sage: wedge.Hilbert_basis() (N(1, 2, 0), N(1, 0, 0), N(0, 0, 1), N(0, 0, -1), N(1, 1, 0)) N(1, 2,  0), N(1, 0,  0), N(0, 0,  1), N(0, 0, -1), N(1, 1,  0) in 3-d lattice N Not full-dimensional cones are ok, too (see http://trac.sagemath.org/sage_trac/ticket/11312):: sage: Cone([(1,1,0), (-1,1,0)]).Hilbert_basis() (N(1, 1, 0), N(-1, 1, 0), N(0, 1, 0)) N( 1, 1, 0), N(-1, 1, 0), N( 0, 1, 0) in 3-d lattice N ALGORITHM: Normaliz. http://www.mathematik.uni-osnabrueck.de/normaliz/ """ if '_Hilbert_basis' in self.__dict__: return self._Hilbert_basis if self.is_strictly_convex(): def not_in_linear_subspace(x): return True else: for y in irreducible+gens): continue irreducible.append(x) Hilbert_basis = tuple(irreducible) self._Hilbert_basis = Hilbert_basis return Hilbert_basis if len(irreducible) == self.nrays(): return self.rays() else: return PointCollection(irreducible, self.lattice()) def Hilbert_coefficients(self, point): r""" sage: cone = Cone([(1,0),(0,1)]) sage: cone.rays() (N(1, 0), N(0, 1)) N(1, 0), N(0, 1) in 2-d lattice N sage: cone.Hilbert_coefficients([3,2]) (3, 2) sage: N = ToricLattice(2) sage: cone = Cone([N(1,0),N(1,2)]) sage: cone.Hilbert_basis() (N(1, 0), N(1, 2), N(1, 1)) N(1, 0), N(1, 2), N(1, 1) in 2-d lattice N sage: cone.Hilbert_coefficients( N(1,1) ) (0, 0, 1) sage: N = ToricLattice(3) sage: cone = Cone([N(1,0,0),N(1,2,0),N(0,0,1),N(0,0,-1)]) sage: cone.Hilbert_basis() (N(1, 2, 0), N(1, 0, 0), N(0, 0, 1), N(0, 0, -1), N(1, 1, 0)) N(1, 2,  0), N(1, 0,  0), N(0, 0,  1), N(0, 0, -1), N(1, 1,  0) in 3-d lattice N sage: cone.Hilbert_coefficients( N(1,1,3) ) (0, 0, 3, 0, 1) """ if self.is_strictly_convex(): def in_linear_subspace(x): return False else: linear_subspace = self.linear_subspace() def in_linear_subspace(x): return x in linear_subspace point = self.lattice()(point) assert point in self, 'The given point is not in the cone!' if point not in self: raise ValueError('The given point is not in the cone!') basis = self.Hilbert_basis() from sage.numerical.mip import MixedIntegerLinearProgram p.solve() return vector(ZZ, p.get_values(x))
• ## sage/geometry/fan.py

diff --git a/sage/geometry/fan.py b/sage/geometry/fan.py
 a Given such "automatic" fans, you may wonder what are their rays and cones:: sage: fan1.rays() (N(1, 0, 0), N(0, 1, 0), N(0, 0, 1), N(-1, 0, 0), N(0, -1, 0), N(0, 0, -1)) sage: fan1.ray_matrix() [ 1  0  0 -1  0  0] [ 0  1  0  0 -1  0] [ 0  0  1  0  0 -1] N( 1,  0,  0), N( 0,  1,  0), N( 0,  0,  1), N(-1,  0,  0), N( 0, -1,  0), N( 0,  0, -1) in 3-d lattice N sage: fan1.generating_cones() (3-d cone of Rational polyhedral fan in 3-d lattice N, 3-d cone of Rational polyhedral fan in 3-d lattice N, The last output is not very illuminating. Let's try to improve it:: sage: for cone in fan1: print cone.rays() (N(1, 0, 0), N(0, 1, 0), N(0, 0, -1)) (N(0, 1, 0), N(-1, 0, 0), N(0, 0, -1)) (N(1, 0, 0), N(0, -1, 0), N(0, 0, -1)) (N(-1, 0, 0), N(0, -1, 0), N(0, 0, -1)) (N(1, 0, 0), N(0, 1, 0), N(0, 0, 1)) (N(0, 1, 0), N(0, 0, 1), N(-1, 0, 0)) (N(1, 0, 0), N(0, 0, 1), N(0, -1, 0)) (N(0, 0, 1), N(-1, 0, 0), N(0, -1, 0)) N(1, 0,  0), N(0, 1,  0), N(0, 0, -1) in 3-d lattice N N( 0, 1,  0), N(-1, 0,  0), N( 0, 0, -1) in 3-d lattice N N(1,  0,  0), N(0, -1,  0), N(0,  0, -1) in 3-d lattice N N(-1,  0,  0), N( 0, -1,  0), N( 0,  0, -1) in 3-d lattice N N(1, 0, 0), N(0, 1, 0), N(0, 0, 1) in 3-d lattice N N( 0, 1, 0), N( 0, 0, 1), N(-1, 0, 0) in 3-d lattice N N(1,  0, 0), N(0,  0, 1), N(0, -1, 0) in 3-d lattice N N( 0,  0, 1), N(-1,  0, 0), N( 0, -1, 0) in 3-d lattice N You can also do :: sage: cone.rays() Traceback (most recent call last): ... AttributeError: 'FinitePoset_with_category.element_class' object has no attribute 'rays' AttributeError: 'FinitePoset_with_category.element_class' object has no attribute 'rays' To get your hands on the "real" cone, you need to do one more step:: sage: cone = cone.element sage: cone.rays() (N(1, 0, 0), N(0, 1, 0)) N(1, 0, 0), N(0, 1, 0) in 3-d lattice N You can check how "good" a fan is:: sage: diamond = lattice_polytope.octahedron(2) sage: P1xP1 = FaceFan(diamond) sage: P1xP1.ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: P1xP1.rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: for cone in P1xP1: print cone.rays() (N(1, 0), N(0, -1)) (N(-1, 0), N(0, -1)) (N(1, 0), N(0, 1)) (N(0, 1), N(-1, 0)) N(1,  0), N(0, -1) in 2-d lattice N N(-1,  0), N( 0, -1) in 2-d lattice N N(1, 0), N(0, 1) in 2-d lattice N N( 0, 1), N(-1, 0) in 2-d lattice N """ if any(d <= 0 for d in polytope.distances([0]*polytope.dim())): raise ValueError("face fans are defined only for polytopes containing" sage: square = lattice_polytope.octahedron(2).polar() sage: P1xP1 = NormalFan(square) sage: P1xP1.ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: P1xP1.rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: for cone in P1xP1: print cone.rays() (N(1, 0), N(0, -1)) (N(-1, 0), N(0, -1)) (N(1, 0), N(0, 1)) (N(0, 1), N(-1, 0)) N(1,  0), N(0, -1) in 2-d lattice N N(-1,  0), N( 0, -1) in 2-d lattice N N(1, 0), N(0, 1) in 2-d lattice N N( 0, 1), N(-1, 0) in 2-d lattice N """ rays = (polytope.facet_normal(i) for i in range(polytope.nfacets())) cones = (vertex.facets() for vertex in polytope.faces(dim=0)) sage: f = sage.geometry.fan.RationalPolyhedralFan( ...                         [(0,)], [v], None) sage: f.rays() ((0, 1),) (0, 1) in Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: TestSuite(f).run() sage: f = Fan([(0,)], [(0,1)]) sage: TestSuite(f).run() ...           rays=[(1,0), (0,1), (-1, 0)], ...           check=False) sage: for cone in f: print cone.rays() (N(1, 0), N(0, 1)) (N(0, 1), N(-1, 0)) N(1, 0), N(0, 1) in 2-d lattice N N( 0, 1), N(-1, 0) in 2-d lattice N """ return iter(self.generating_cones()) sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) sage: fan = Fan([cone1, cone2]) sage: fan.ray_matrix() [ 0  1 -1] [ 1  0  0] sage: fan.rays() N( 0, 1), N( 1, 0), N(-1, 0) in 2-d lattice N sage: for cone in fan: print cone.ambient_ray_indices() (0, 1) (2,) sage: # Timing information will depend on your machine sage: new_fan = fan._subdivide_palp(new_rays, True) R:1/1  C:2  T:...(ms)  T/new:...(ms)  T/all:...(ms) sage: new_fan.ray_matrix() [1 0 1] [0 1 1] sage: new_fan.rays() N(1, 0), N(0, 1), N(1, 1) in 2-d lattice N sage: for cone in new_fan: print cone.ambient_ray_indices() (1, 2) (0, 2) # Convert lattice polytopes to cones new_fan_rays = list(self.rays()) new_fan_rays.extend(ray for ray in new_rays if ray not in self.ray_set()) if ray not in self.rays().set()) cones = tuple(tuple(sorted(new_fan_rays.index(cone_polytope.vertex(v)) for v in range(cone_polytope.nvertices() - 1))) for cone_polytope in cone_polytopes) sage: cone2 = Cone([(1,0), (0,1)]) sage: f = Fan([cone1, cone2]) sage: f.rays() (N(0, 1), N(0, -1), N(1, 0)) N(0,  1), N(0, -1), N(1,  0) in 2-d lattice N sage: f.cone_containing(0)  # ray index 1-d cone of Rational polyhedral fan in 2-d lattice N sage: f.cone_containing(0, 1) # ray indices ... ValueError: there is no cone in Rational polyhedral fan in 2-d lattice N containing all of the given rays! Rays: (N(0, 1), N(0, -1)) containing all of the given rays! Ray indices: [0, 1] sage: f.cone_containing(0, 2) # ray indices 2-d cone of Rational polyhedral fan in 2-d lattice N sage: f.cone_containing((0,1))  # point sage: fan = Fan(cones=[(0,1,2,3), (0,1,4)], ...       rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)]) sage: fan.cone_containing(0).rays() (N(1, 1, 1),) N(1, 1, 1) in 3-d lattice N """ if not points: return self.cones(dim=0)[0] generating_cones.intersection_update(self._ray_to_cones(ray)) if not generating_cones: raise ValueError("there is no cone in %s containing all of " "the given rays! Rays: %s" % (self, self.rays(rays))) "the given rays! Ray indices: %s" % (self, rays)) containing_cone = self.generating_cone(generating_cones.pop()) for cone in generating_cones: containing_cone = containing_cone.intersection( sage: cone1 = Cone([(1,0), (0,1)]) sage: cone2 = Cone([(-1,0)]) sage: fan = Fan([cone1, cone2]) sage: fan.ray_matrix() [ 0  1 -1] [ 1  0  0] sage: fan.rays() N( 0, 1), N( 1, 0), N(-1, 0) in 2-d lattice N sage: for cone in fan: print cone.ambient_ray_indices() (0, 1) (2,) sage: e_ray 1-d cone of Rational polyhedral fan in 3-d lattice N sage: e_ray.rays() (N(0, -1, 1),) N(0, -1, 1) in 3-d lattice N sage: e_ray is ray False sage: e_ray.is_equivalent(ray) except ValueError: raise ValueError("%s does not belong to %s!" % (cone, self)) return result @cached_method def Gale_transform(self): r""" Return the Gale transform of self. sage: _.base_ring() Integer Ring """ if "_Gale_transform" not in self.__dict__: m = self.ray_matrix().augment(matrix(self.lattice_dim(), 1)) m = m.stack(matrix([1]*m.ncols())) self._Gale_transform = matrix(ZZ, m.transpose().integer_kernel().matrix()) return self._Gale_transform m = self.rays().matrix().stack(matrix(ZZ, 1, self.lattice_dim())) m = m.augment(matrix(ZZ, m.nrows(), 1, [1]*m.nrows())) return matrix(ZZ, m.integer_kernel().matrix()) def generating_cone(self, n): r""" if (self.lattice() != other.lattice() or self.dim() != other.dim() or self.ngenerating_cones() != other.ngenerating_cones() or self.ray_set() != other.ray_set()): or self.rays().set() != other.rays().set()): return False # Now we need to really compare cones, which can take a while return sorted(sorted(cone.rays()) for cone in self) \ sage: fan.is_smooth(codim=1) True sage: fan.generating_cone(0).rays() (N(-1, 1), N(-1, -1)) sage: fan.generating_cone(0).ray_matrix().det() N(-1,  1), N(-1, -1) in 2-d lattice N sage: fan.generating_cone(0).rays().matrix().det() 2 """ if codim is None or codim < 0: else: rays = [] rays.extend(ray for ray in normalize_rays(new_rays, self.lattice()) if ray not in self.ray_set()) if ray not in self.rays().set()) if not rays: return self # Nothing has to be done if self.lattice().zero() in rays: + 3-d cone of Rational polyhedral fan in 3-d lattice N - 3-d cone of Rational polyhedral fan in 3-d lattice N + 3-d cone of Rational polyhedral fan in 3-d lattice N sage: [ matrix(cone.ray_basis()).det() for cone in fan.generating_cones() ] sage: [cone.rays().basis().matrix().det() ...    for cone in fan.generating_cones()] [-1, 1, -1, 1] A non-full dimensional fan:: outward_v = [ Q.lift(q) for q in Q.gens() ] outward_vectors[c] = outward_v orientation = sign(matrix(outward_v + list(c.ray_basis())).det()) orientation = sign(matrix(outward_v + list(c.rays().basis())).det()) generating_cones.append(tuple([orientation, c])) boundaries = {self:FormalSum(generating_cones)} for d in range(dim, -1, -1): for c in self(d): c_boundary = [] c_matrix = matrix(outward_vectors[c] + list(c.ray_basis())) c_matrix = matrix(outward_vectors[c] + list(c.rays().basis())) c_matrix_inv = c_matrix.inverse() for facet in c.facets(): outward_ray_indices = set(c.ambient_ray_indices()) \ .difference(set(facet.ambient_ray_indices())) outward_vector = - sum(self.ray(i) for i in outward_ray_indices) outward_vectors[facet] = [outward_vector] + outward_vectors[c] facet_matrix = matrix(outward_vectors[facet] + list(facet.ray_basis())) facet_matrix = matrix(outward_vectors[facet] + list(facet.rays().basis())) orientation = sign((c_matrix_inv * facet_matrix).det()) c_boundary.append(tuple([orientation, facet])) boundaries[c] = FormalSum(c_boundary)
• ## sage/geometry/fan_morphism.py

diff --git a/sage/geometry/fan_morphism.py b/sage/geometry/fan_morphism.py
 a [0 0] Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N sage: fm.domain_fan().ray_matrix() [-1  1 -1  1  0  0] [ 1  1 -1 -1 -1  1] sage: normal.ray_matrix() [-1  1 -1  1] [ 1  1 -1 -1] sage: fm.domain_fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1), N( 0, -1), N( 0,  1) in 2-d lattice N sage: normal.rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1) in 2-d lattice N As you see, it was necessary to insert two new rays (to prevent "upper" and "lower" cones of the normal fan from being mapped to the whole x-axis). sage: fm = FanMorphism(phi, face) sage: fm.codomain_fan() Rational polyhedral fan in 2-d lattice N sage: fm.codomain_fan().ray_matrix() [ 1 -1] [ 0  0] sage: fm.codomain_fan().rays() N( 1, 0), N(-1, 0) in 2-d lattice N Now we demonstrate a more subtle example. We take the first quadrant as our domain fan. Then we divide the first quadrant into three cones, throw away ValueError: codomain (fan) must be given explicitly if morphism is given by a matrix! sage: fm = FanMorphism(identity_matrix(2), quadrant_bl, ZZ^2) sage: fm.codomain_fan().ray_matrix()  # indirect doctest [1 0 1] [0 1 1] sage: fm.codomain_fan().rays()  # indirect doctest (1, 0), (0, 1), (1, 1) in Ambient free module of rank 2 over the principal ideal domain Integer Ring """ # We literally try to construct the image fan and hope that it works. # If it does not, the fan constructor will raise an exception. is not contained in a single cone of the codomain fan! sage: fm = FanMorphism(identity_matrix(2), quadrant, ...                    quadrant_bl, subdivide=True) sage: fm.domain_fan().ray_matrix()  # indirect doctest [1 0 1] [0 1 1] sage: fm.domain_fan().rays()  # indirect doctest N(1, 0), N(0, 1), N(1, 1) in 2-d lattice N Now we demonstrate a more subtle example. We take the first quadrant as our domain_fan. Then we divide the first quadrant into three sage: Sigma_prime = FaceFan(lattice_polytope.octahedron(3)) sage: fm = FanMorphism(identity_matrix(3), ...                    Sigma, Sigma_prime, subdivide=True) sage: fm.domain_fan().ray_matrix() [ 1  1  1] [ 1 -1  0] [ 0  0  0] sage: fm.domain_fan().rays() N(1,  1, 0), N(1, -1, 0), N(1,  0, 0) in 3-d lattice N sage: [cone.ambient_ray_indices() for cone in fm.domain_fan()] [(0, 2), (1, 2)] sage: F1 = Fan(cones=[(0,1,2), (1,2,3)], ...            rays=[(1,1,1), (1,1,-1), (1,-1,1), (1,-1,-1)], ...            lattice=N3) sage: F1.ray_matrix() [ 1  1  1  1] [ 1  1 -1 -1] [ 1 -1  1 -1] sage: F1.rays() N3(1,  1,  1), N3(1,  1, -1), N3(1, -1,  1), N3(1, -1, -1) in 3-d lattice N3 sage: [phi(ray) for ray in F1.rays()] [N2(2, 1), N2(0, 1), N2(2, -1), N2(0, -1)] sage: F2 = Fan(cones=[(0,1,2), (1,2,3)], ...            rays=[(1,1,1), (1,1,-1), (1,2,1), (1,2,-1)], ...            lattice=N3) sage: F2.ray_matrix() [ 1  1  1  1] [ 1  1  2  2] [ 1 -1  1 -1] sage: F2.rays() N3(1, 1,  1), N3(1, 1, -1), N3(1, 2,  1), N3(1, 2, -1) in 3-d lattice N3 sage: [phi(ray) for ray in F2.rays()] [N2(2, 1), N2(0, 1), N2(2, 2), N2(0, 2)] sage: F3 = Fan(cones=[(0,1), (1,2)], sage: fm = FanMorphism(matrix(2, 1, [1,-1]), fan, ToricLattice(1)) sage: fm.kernel_fan() Rational polyhedral fan in Sublattice sage: _.ray_matrix() [1] [1] sage: _.rays() N(1, 1) in Sublattice sage: fm.kernel_fan().cones() ((0-d cone of Rational polyhedral fan in Sublattice ,), (1-d cone of Rational polyhedral fan in Sublattice ,)) Consider a projection of a del Pezzo surface onto the projective line:: sage: Sigma = toric_varieties.dP6().fan() sage: Sigma.ray_matrix() [ 0 -1 -1  0  1  1] [ 1  0 -1 -1  0  1] sage: Sigma.rays() N( 0,  1), N(-1,  0), N(-1, -1), N( 0, -1), N( 1,  0), N( 1,  1) in 2-d lattice N sage: Sigma_p = toric_varieties.P1().fan() sage: phi = FanMorphism(matrix([[1], [-1]]), Sigma, Sigma_p) sage: psi.codomain().gens() (N(1, 1),) sage: psi.codomain_fan().ray_matrix() [ 1 -1] [ 1 -1] sage: psi.codomain_fan().rays() N( 1,  1), N(-1, -1) in Sublattice Restriction to image returns exactly the same map if the corresponding map of vector spaces is surjective, e.g. in the case of double
• ## sage/geometry/point_collection.pyx

diff --git a/sage/geometry/point_collection.pyx b/sage/geometry/point_collection.pyx
 a - Andrey Novoseltsev (2011-04-25): initial version, based on cone module. - Andrey Novoseltsev (2012-03-06): additions and doctest changes while switching cones to use point collections. EXAMPLES: The idea behind :class:point collections  is to have a * behaves like a tuple *without significant performance penalty*:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c[1] N(1, 0, 1) sage: for point in c: point N(0, 1, 1) N(1, 1, 1) * prints like a matrix with points represented by columns and with some indication of the ambient space:: * prints in a convenient way and with clear indication of the ambient space:: sage: c [0 1 0 1] [0 0 1 1] [1 1 1 1] N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1) in 3-d lattice N * allows (cached) access to alternative representations:: * allows introduction of additional methods:: sage: c.basis() [0 1 0] [0 0 1] [1 1 1] N(0, 0, 1), N(1, 0, 1), N(0, 1, 1) in 3-d lattice N Examples of natural point collections include ray and line generators of cones, """ #***************************************************************************** #       Copyright (C) 2011 Andrey Novoseltsev #       Copyright (C) 2012 Andrey Novoseltsev # #  Distributed under the terms of the GNU General Public License (GPL) #  as published by the Free Software Foundation; either version 2 of from sage.structure.sage_object cimport SageObject from sage.matrix.all import column_matrix from sage.matrix.all import matrix from sage.misc.all import latex sage: from sage.geometry.point_collection import is_PointCollection sage: is_PointCollection(1) False sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: is_PointCollection(c.rays()) # TODO: make it True False sage: c = PointCollection(c.rays(), c.lattice()) sage: is_PointCollection(c) sage: is_PointCollection(c.rays()) True """ return isinstance(x, PointCollection) _output_format = "default" cdef class PointCollection(SageObject): r""" Create a point collection. TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c() [] Empty collection in 3-d lattice N sage: c(2,1) [0 1] [1 0] [1 1] N(0, 1, 1), N(1, 0, 1) in 3-d lattice N sage: c(range(4)) == c True TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: cmp(c, c) 0 sage: cmp(c, 1) * cmp(1, c) EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c[0] N(0, 0, 1) """ TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: hash(c) == hash(c) True """ TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: for point in c: print point N(0, 0, 1) N(1, 0, 1) EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: len(c) 4 """ return len(self._points) def __list__(self): r""" Return a list of points of self. OUTPUT: - a list. TESTS:: sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: list(c) [N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1)] """ return list(self._points) def __reduce__(self): r""" Prepare self for pickling. TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: loads(dumps(c)) [0 1 0 1] [0 0 1 1] [1 1 1 1] N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1) in 3-d lattice N sage: loads(dumps(c)) == c True """ return (PointCollection, (self._points, self._module)) def __tuple__(self): r""" Return the tuple of points of self. OUTPUT: - a tuple. TESTS:: sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: tuple(c) (N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1)) """ return self._points def _latex_(self): r""" Return a LaTeX representation of self. TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: print c._latex_() \left(\begin{array}{rrrr} 0 & 1 & 0 & 1 \\ 0 & 0 & 1 & 1 \\ 1 & 1 & 1 & 1 \end{array}\right)_{N} \left(\left(0,\,0,\,1\right)_{N}, \left(1,\,0,\,1\right)_{N}, \left(0,\,1,\,1\right)_{N}, \left(1,\,1,\,1\right)_{N}\right)_{N} """ return r"%s_{%s}" % (latex(self.matrix()), latex(self.module())) global _output_format if _output_format in ["default", "tuple"]: r = latex(tuple(self)) elif _output_format == "matrix": r = latex(self.matrix()) elif _output_format == "column matrix": r = latex(self.column_matrix()) elif _output_format == "separated column matrix": r = latex(self.column_matrix()) r = r.replace("r" * len(self), "|".join("r" * len(self))) return r"%s_{%s}" % (r, latex(self.module())) def _matrix_(self, ring=None): r""" Return a matrix whose rows are points of self. INPUT: - ring -- a base ring for the returned matrix (default: base ring of :meth:module of self). OUTPUT: - a :class:matrix . EXAMPLES:: sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: matrix(c) [0 0 1] [1 0 1] [0 1 1] [1 1 1] """ if ring is None: return self.matrix() else: return self.matrix().change_ring(ring) def _repr_(self): r""" TESTS:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: print c._repr_() [0 1 0 1] [0 0 1 1] [1 1 1 1] N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1) in 3-d lattice N """ return "%s\nin %s" % (self.matrix(), self.module()) global _output_format if _output_format == "default": r = map(repr, self) r = [point.split(",") for point in r] if not r: r = "Empty collection" else: if "(" in r[0][0]: delimiter = "(" elif "[" in r[0][0]: delimiter = "[" else: raise ValueError("cannot parse point representation!") heads = [] for point in r: head, point[0] = point[0].rsplit(delimiter, 1) heads.append(head + delimiter) format = "{{:<{}}}".format(max(map(len, heads))) widths = [0] * len(r[0]) for point in r: for i, coordinate in enumerate(point): widths[i] = max(widths[i], len(coordinate)) format += ",".join("{{:>{}}}".format(width) for width in widths) r = ",\n".join([format.format(head, *point) for head, point in zip(heads, r)]) elif _output_format == "tuple": r = tuple(self) elif _output_format == "matrix": r = self.matrix() else: r = self.column_matrix() return "{}\nin {}".format(r, self.module()) def basis(self): r""" EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.basis() [0 1 0] [0 0 1] [1 1 1] N(0, 0, 1), N(1, 0, 1), N(0, 1, 1) in 3-d lattice N Calling this method twice will always return *exactly the same* point True """ if self._basis is None: self._basis = self(self.matrix().pivots()) self._basis = self(self.matrix().pivot_rows()) return self._basis def cardinality(self): EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.cardinality() 4 """ EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,1,1)]).rays() sage: c.cartesian_product(c) [0 1 0 1] [0 1 0 1] [1 1 1 1] [0 0 1 1] [0 0 1 1] [1 1 1 1] N+N(0, 0, 1, 0, 0, 1), N+N(1, 1, 1, 0, 0, 1), N+N(0, 0, 1, 1, 1, 1), N+N(1, 1, 1, 1, 1, 1) in 6-d lattice N+N """ assert is_PointCollection(other) pq.set_immutable() return PointCollection(PQ, module) def column_matrix(self): r""" Return a matrix whose columns are points of self. OUTPUT: - a :class:matrix . EXAMPLES:: sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.column_matrix() [0 1 0 1] [0 0 1 1] [1 1 1 1] """ return self.matrix().transpose() def dimension(self): r""" Return the dimension of the space spanned by points of self. EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,1,1)]).rays() sage: c.dimension() 2 sage: c.dim() EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.dual_module() 3-d lattice M """ # TODO: add support for torsion modules as well? return M.base_ring() ** M.dimension() def index(self, *args): r""" Return the index of the first occurrence of point in self. INPUT: - point -- a point of self; - start -- (optional) an integer, if given, the search will start at this position; - stop -- (optional) an integer, if given, the search will stop at this position. OUTPUT: - an integer if point is in self[start:stop], otherwise a ValueError exception is raised. EXAMPLES:: sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.index((0,1,1)) Traceback (most recent call last): ... ValueError: tuple.index(x): x not in tuple Note that this was not a mistake: the *tuple* (0,1,1) is *not* a point of c! We need to pass actual element of the ambient module of c to get their indices:: sage: N = c.module() sage: c.index(N(0,1,1)) 2 sage: c[2] N(0, 1, 1) """ return self._points.index(*args) def matrix(self): r""" Return a matrix whose columns are points of self. Return a matrix whose rows are points of self. OUTPUT: EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.matrix() [0 1 0 1] [0 0 1 1] [1 1 1 1] [0 0 1] [1 0 1] [0 1 1] [1 1 1] """ if self._matrix is None: M = column_matrix(self._module.base_ring(), len(self._points), self._module.degree(), self._points) M = matrix(self._module.base_ring(), len(self._points), self._module.degree(), self._points) M.set_immutable() self._matrix = M return self._matrix EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.module() 3-d lattice N """ return self._module return self._module @classmethod    # @staticmethod does not work in Cython so far def output_format(cls, format=None): r""" Return or set the output format for **ALL** point collections. INPUT: - format -- (optional) if given, must be one of the strings * "default" -- output one point per line with vertical alignment of coordinates in text mode, same as "tuple" for LaTeX; * "tuple" -- output tuple(self) with lattice information; * "matrix" -- output :meth:matrix with lattice information; * "column matrix" -- output :meth:column_matrix with lattice information; * "separated column matrix" -- same as "column matrix" for text mode, for LaTeX separate columns by lines (not shown by jsMath). OUTPUT: - a string with the current format (only if format was omitted). This function affects both regular and LaTeX output. EXAMPLES:: sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1) in 3-d lattice N sage: c.output_format() 'default' sage: c.output_format("tuple") sage: c (N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1)) in 3-d lattice N sage: c.output_format("matrix") sage: c [0 0 1] [1 0 1] [0 1 1] [1 1 1] in 3-d lattice N sage: c.output_format("column matrix") sage: c [0 1 0 1] [0 0 1 1] [1 1 1 1] in 3-d lattice N sage: c.output_format("separated column matrix") sage: c [0 1 0 1] [0 0 1 1] [1 1 1 1] in 3-d lattice N Note that the last two outpus are identical, separators are only inserted in the LaTeX mode:: sage: latex(c) \left(\begin{array}{r|r|r|r} 0 & 1 & 0 & 1 \\ 0 & 0 & 1 & 1 \\ 1 & 1 & 1 & 1 \end{array}\right)_{N} Since this is a static method, you can call it for the class directly:: sage: from sage.geometry.point_collection import PointCollection sage: PointCollection.output_format("default") sage: c N(0, 0, 1), N(1, 0, 1), N(0, 1, 1), N(1, 1, 1) in 3-d lattice N """ global _output_format if format is None: return _output_format assert format in ["default", "tuple", "matrix", "column matrix", "separated column matrix"] _output_format = format def set(self): r""" EXAMPLES:: sage: from sage.geometry.point_collection import PointCollection sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]) sage: c = PointCollection(c.rays(), c.lattice()) sage: c = Cone([(0,0,1), (1,0,1), (0,1,1), (1,1,1)]).rays() sage: c.set() frozenset([N(0, 1, 1), N(1, 1, 1), N(0, 0, 1), N(1, 0, 1)]) """
• ## sage/geometry/triangulation/element.py

diff --git a/sage/geometry/triangulation/element.py b/sage/geometry/triangulation/element.py
 a sage: fan Rational polyhedral fan in 3-d lattice N sage: fan.rays() (N(1, 1, 0), N(1, 3, 1), N(1, 2, 3), N(1, 0, 2), N(1, 1, 1), N(1, 1, 2), N(1, 2, 1), N(1, 2, 2)) N(1, 1, 0), N(1, 3, 1), N(1, 2, 3), N(1, 0, 2), N(1, 1, 1), N(1, 1, 2), N(1, 2, 1), N(1, 2, 2) in 3-d lattice N """ from sage.geometry.fan import Fan if origin is None: sage: N = triangulation.normal_cone();  N 4-d cone in 4-d lattice sage: N.rays() ((-1, 0, 0, 0), (1, 0, 1, 0), (-1, 0, -1, 0), (1, 0, 0, -1), (-1, 0, 0, 1), (1, 1, 0, 0), (-1, -1, 0, 0)) (-1,  0,  0,  0), ( 1,  0,  1,  0), (-1,  0, -1,  0), ( 1,  0,  0, -1), (-1,  0,  0,  1), ( 1,  1,  0,  0), (-1, -1,  0,  0) in Ambient free module of rank 4 over the principal ideal domain Integer Ring sage: N.dual().rays() ((-1, 1, 1, -1),) (-1, 1, 1, -1) in Ambient free module of rank 4 over the principal ideal domain Integer Ring TESTS::
• ## sage/schemes/generic/algebraic_scheme.py

diff --git a/sage/schemes/generic/algebraic_scheme.py b/sage/schemes/generic/algebraic_scheme.py
 a polynomials = [ p.subs(inhomogenize) for p in self.defining_polynomials() ] # map the monomial x^{D_m} to m, see reference. n_rho_matrix = cone.ray_matrix() n_rho_matrix = cone.rays().matrix() def pullback_polynomial(p): result = R.zero() for coefficient, monomial in p: exponent = monomial.exponents()[0] exponent = [ exponent[i] for i in cone.ambient_ray_indices() ] exponent = vector(ZZ,exponent) m = n_rho_matrix.solve_left(exponent) m = n_rho_matrix.solve_right(exponent) assert all(x in ZZ for x in m), \ 'The polynomial '+str(p)+' does not define a ZZ-divisor!' m_coeffs = dualcone.Hilbert_coefficients(m)
• ## sage/schemes/toric/divisor.py

diff --git a/sage/schemes/toric/divisor.py b/sage/schemes/toric/divisor.py
 a sage: Kc = dP6.Kaehler_cone(); Kc 4-d cone in 4-d lattice sage: Kc.rays() (Divisor class [0, 1, 1, 0], Divisor class [0, 0, 1, 1], Divisor class [1, 1, 0, 0], Divisor class [1, 1, 1, 0], Divisor class [0, 1, 1, 1]) Divisor class [0, 1, 1, 0], Divisor class [0, 0, 1, 1], Divisor class [1, 1, 0, 0], Divisor class [1, 1, 1, 0], Divisor class [0, 1, 1, 1] in Basis lattice of The toric rational divisor class group of a 2-d CPR-Fano toric variety covered by 6 affine patches sage: Kc.ray(1).lift() V(y) + V(v) assert cone.ambient() is fan b = vector(self.coefficient(i) for i in cone.ambient_ray_indices()) A = cone.ray_matrix() A = cone.rays().column_matrix() try: if cone.dim() == X.dimension(): # either unique solution or ValueError (if not QQ-Cartier) sage: X.rational_class_group().dimension() 4 sage: X.Kaehler_cone().rays() (Divisor class [1, 0, 0, 0],) Divisor class [1, 0, 0, 0] in Basis lattice of The toric rational divisor class group of a 3-d toric variety covered by 7 affine patches sage: antiK = -X.K() sage: antiK.divisor_class() Divisor class [2, 0, 0, 0]
• ## sage/schemes/toric/fano_variety.py

diff --git a/sage/schemes/toric/fano_variety.py b/sage/schemes/toric/fano_variety.py
 a 2-d CPR-Fano toric variety covered by 4 affine patches sage: P1xP1.fan() Rational polyhedral fan in 2-d lattice N sage: P1xP1.fan().ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: P1xP1.fan().rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N "Unfortunately," this variety is smooth to start with and we cannot perform any subdivisions of the underlying fan without leaving the We will construct several varieties associated to it:: sage: FTV = CPRFanoToricVariety(Delta_polar=square) sage: FTV.fan().ray_matrix() [-1  1 -1  1] [ 1  1 -1 -1] sage: FTV.fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1) in 2-d lattice N sage: FTV.gens() (z0, z1, z2, z3) sage: FTV = CPRFanoToricVariety(Delta_polar=square, ...         coordinate_points=[0,1,2,3,8]) sage: FTV.fan().ray_matrix() [-1  1 -1  1  1] [ 1  1 -1 -1  0] sage: FTV.fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1), N( 1,  0) in 2-d lattice N sage: FTV.gens() (z0, z1, z2, z3, z8) sage: FTV = CPRFanoToricVariety(Delta_polar=square, ...         coordinate_points=[8,0,2,1,3], ...         coordinate_names="x+") sage: FTV.fan().ray_matrix() [ 1 -1 -1  1  1] [ 0  1 -1  1 -1] sage: FTV.fan().rays() N( 1,  0), N(-1,  1), N(-1, -1), N( 1,  1), N( 1, -1) in 2-d lattice N sage: FTV.gens() (x8, x0, x2, x1, x3) sage: FTV = CPRFanoToricVariety(Delta_polar=square, ...         coordinate_points="all", ...         coordinate_names="x y Z+") sage: FTV.fan().ray_matrix() [-1  1 -1  1 -1  0  0  1] [ 1  1 -1 -1  0 -1  1  0] sage: FTV.fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1), N(-1,  0), N( 0, -1), N( 0,  1), N( 1,  0) in 2-d lattice N sage: FTV.gens() (x, y, Z2, Z3, Z4, Z5, Z7, Z8) sage: FTV = CPRFanoToricVariety(Delta_polar=square, ...         coordinate_points=[0,1,2,3,4], ...         charts=charts) sage: FTV.fan().ray_matrix() [-1  1 -1  1 -1] [ 1  1 -1 -1  0] sage: FTV.fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1), N(-1,  0) in 2-d lattice N sage: [cone.ambient_ray_indices() for cone in FTV.fan()] [(0, 1), (1, 3), (2, 3), (2, 4), (0, 4)] ...         coordinate_points=[0,1,2,3,4], ...         charts=bad_charts, ...         check=False) sage: FTV.fan().ray_matrix() [-1  1 -1  1 -1] [ 1  1 -1 -1  0] sage: FTV.fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1), N(-1,  0) in 2-d lattice N sage: [cone.ambient_ray_indices() for cone in FTV.fan()] [(0, 1), (1, 3), (2, 3), (2, 4), (0, 4), (2, 4), (0, 4)] raise ValueError("given charts do not form a complete fan!") # Subdivide this fan to use all required points fan = fan.subdivide(new_rays=(ray for ray in rays if ray not in fan.ray_set()), if ray not in fan.rays().set()), make_simplicial=make_simplicial) # Now create yet another fan making sure that the order of the rays is # the same as requested (it is a bit difficult to get it from the start) sage: P1xP2 = P1.cartesian_product(P2); P1xP2 3-d CPR-Fano toric variety covered by 6 affine patches sage: P1xP2.fan().rays() (N+N(1, 0, 0), N+N(-1, 0, 0), N+N(0, 1, 0), N+N(0, 0, 1), N+N(0, -1, -1)) N+N( 1,  0,  0), N+N(-1,  0,  0), N+N( 0,  1,  0), N+N( 0,  0,  1), N+N( 0, -1, -1) in 3-d lattice N+N sage: P1xP2.Delta_polar() A lattice polytope: 3-dimensional, 5 vertices. """
• ## sage/schemes/toric/library.py

diff --git a/sage/schemes/toric/library.py b/sage/schemes/toric/library.py
 a sage: dP6 = toric_varieties.dP6() sage: dP6 2-d CPR-Fano toric variety covered by 6 affine patches sage: dP6.fan().ray_matrix() [ 0 -1 -1  0  1  1] [ 1  0 -1 -1  0  1] sage: dP6.fan().rays() N( 0,  1), N(-1,  0), N(-1, -1), N( 0, -1), N( 1,  0), N( 1,  1) in 2-d lattice N sage: dP6.gens() (x, u, y, v, z, w) """ sage: dP7 = toric_varieties.dP7() sage: dP7 2-d CPR-Fano toric variety covered by 5 affine patches sage: dP7.fan().ray_matrix() [ 0 -1 -1  0  1] [ 1  0 -1 -1  0] sage: dP7.fan().rays() N( 0,  1), N(-1,  0), N(-1, -1), N( 0, -1), N( 1,  0) in 2-d lattice N sage: dP7.gens() (x, u, y, v, z) """ sage: dP8 = toric_varieties.dP8() sage: dP8 2-d CPR-Fano toric variety covered by 4 affine patches sage: dP8.fan().ray_matrix() [ 1  0 -1  1] [ 1  1 -1  0] sage: dP8.fan().rays() N( 1,  1), N( 0,  1), N(-1, -1), N( 1,  0) in 2-d lattice N sage: dP8.gens() (t, x, y, z) """ sage: P1xP1 = toric_varieties.P1xP1() sage: P1xP1 2-d CPR-Fano toric variety covered by 4 affine patches sage: P1xP1.fan().ray_matrix() [ 1 -1  0  0] [ 0  0  1 -1] sage: P1xP1.fan().rays() N( 1,  0), N(-1,  0), N( 0,  1), N( 0, -1) in 2-d lattice N sage: P1xP1.gens() (s, t, x, y) """ sage: P1xP1_Z2 = toric_varieties.P1xP1_Z2() sage: P1xP1_Z2 2-d CPR-Fano toric variety covered by 4 affine patches sage: P1xP1_Z2.fan().ray_matrix() [ 1 -1 -1  1] [ 1 -1  1 -1] sage: P1xP1_Z2.fan().rays() N( 1,  1), N(-1, -1), N(-1,  1), N( 1, -1) in 2-d lattice N sage: P1xP1_Z2.gens() (s, t, x, y) sage: P1xP1_Z2.Chow_group().degree(1) sage: P1 = toric_varieties.P1() sage: P1 1-d CPR-Fano toric variety covered by 2 affine patches sage: P1.fan().ray_matrix() [ 1 -1] sage: P1.fan().rays() N( 1), N(-1) in 1-d lattice N sage: P1.gens() (s, t) """ sage: P2 = toric_varieties.P2() sage: P2 2-d CPR-Fano toric variety covered by 3 affine patches sage: P2.fan().ray_matrix() [ 1  0 -1] [ 0  1 -1] sage: P2.fan().rays() N( 1,  0), N( 0,  1), N(-1, -1) in 2-d lattice N sage: P2.gens() (x, y, z) """ sage: P3 = toric_varieties.P(3) sage: P3 3-d CPR-Fano toric variety covered by 4 affine patches sage: P3.fan().ray_matrix() [ 1  0  0 -1] [ 0  1  0 -1] [ 0  0  1 -1] sage: P3.fan().rays() N( 1,  0,  0), N( 0,  1,  0), N( 0,  0,  1), N(-1, -1, -1) in 3-d lattice N sage: P3.gens() (z0, z1, z2, z3) """ sage: A1 = toric_varieties.A1() sage: A1 1-d affine toric variety sage: A1.fan().ray_matrix() [1] sage: A1.fan().rays() N(1) in 1-d lattice N sage: A1.gens() (z,) """ sage: A2 = toric_varieties.A2() sage: A2 2-d affine toric variety sage: A2.fan().ray_matrix() [1 0] [0 1] sage: A2.fan().rays() N(1, 0), N(0, 1) in 2-d lattice N sage: A2.gens() (x, y) """ sage: A3 = toric_varieties.A(3) sage: A3 3-d affine toric variety sage: A3.fan().ray_matrix() [1 0 0] [0 1 0] [0 0 1] sage: A3.fan().rays() N(1, 0, 0), N(0, 1, 0), N(0, 0, 1) in 3-d lattice N sage: A3.gens() (z0, z1, z2) """ sage: A2_Z2 = toric_varieties.A2_Z2() sage: A2_Z2 2-d affine toric variety sage: A2_Z2.fan().ray_matrix() [1 1] [0 2] sage: A2_Z2.fan().rays() N(1, 0), N(1, 2) in 2-d lattice N sage: A2_Z2.gens() (x, y) """ sage: P1xA1 = toric_varieties.P1xA1() sage: P1xA1 2-d toric variety covered by 2 affine patches sage: P1xA1.fan().ray_matrix() [ 1 -1  0] [ 0  0  1] sage: P1xA1.fan().rays() N( 1, 0), N(-1, 0), N( 0, 1) in 2-d lattice N sage: P1xA1.gens() (s, t, z) """ sage: Conifold = toric_varieties.Conifold() sage: Conifold 3-d affine toric variety sage: Conifold.fan().ray_matrix() [0 0 1 1] [0 1 0 1] [1 1 1 1] sage: Conifold.fan().rays() N(0, 0, 1), N(0, 1, 1), N(1, 0, 1), N(1, 1, 1) in 3-d lattice N sage: Conifold.gens() (u, x, y, v) """ EXAMPLES:: sage: dP6xdP6 = toric_varieties.dP6xdP6()   # long time (20s on sage.math, 2011) sage: dP6xdP6                               # long time sage: dP6xdP6 = toric_varieties.dP6xdP6() sage: dP6xdP6 4-d CPR-Fano toric variety covered by 36 affine patches sage: dP6xdP6.fan().ray_matrix()            # long time [ 0 -1 -1  0  1  1  0  0  0  0  0  0] [ 1  0 -1 -1  0  1  0  0  0  0  0  0] [ 0  0  0  0  0  0  0 -1 -1  0  1  1] [ 0  0  0  0  0  0  1  0 -1 -1  0  1] sage: dP6xdP6.gens()                        # long time sage: dP6xdP6.fan().rays() N( 0,  1,  0,  0), N(-1,  0,  0,  0), N(-1, -1,  0,  0), N( 0, -1,  0,  0), N( 1,  0,  0,  0), N( 1,  1,  0,  0), N( 0,  0,  0,  1), N( 0,  0, -1,  0), N( 0,  0, -1, -1), N( 0,  0,  0, -1), N( 0,  0,  1,  0), N( 0,  0,  1,  1) in 4-d lattice N sage: dP6xdP6.gens() (x0, x1, x2, x3, x4, x5, y0, y1, y2, y3, y4, y5) """ return self._make_CPRFanoToricVariety('dP6xdP6', names) sage: Cube_face_fan = toric_varieties.Cube_face_fan() sage: Cube_face_fan 3-d CPR-Fano toric variety covered by 6 affine patches sage: Cube_face_fan.fan().ray_matrix() [ 1  1 -1 -1 -1 -1  1  1] [ 1 -1  1 -1 -1  1 -1  1] [ 1  1  1  1 -1 -1 -1 -1] sage: Cube_face_fan.fan().rays() N( 1,  1,  1), N( 1, -1,  1), N(-1,  1,  1), N(-1, -1,  1), N(-1, -1, -1), N(-1,  1, -1), N( 1, -1, -1), N( 1,  1, -1) in 3-d lattice N sage: Cube_face_fan.gens() (z0, z1, z2, z3, z4, z5, z6, z7) """ sage: Cube_sublattice = toric_varieties.Cube_sublattice() sage: Cube_sublattice 3-d CPR-Fano toric variety covered by 6 affine patches sage: Cube_sublattice.fan().ray_matrix() [ 1  0  0 -1 -1  0  0  1] [ 0  1  0  1  0 -1  0 -1] [ 0  0  1  1  0  0 -1 -1] sage: Cube_sublattice.fan().rays() N( 1,  0,  0), N( 0,  1,  0), N( 0,  0,  1), N(-1,  1,  1), N(-1,  0,  0), N( 0, -1,  0), N( 0,  0, -1), N( 1, -1, -1) in 3-d lattice N sage: Cube_sublattice.gens() (z0, z1, z2, z3, z4, z5, z6, z7) sage: Cube_nonpolyhedral = toric_varieties.Cube_nonpolyhedral() sage: Cube_nonpolyhedral 3-d toric variety covered by 6 affine patches sage: Cube_nonpolyhedral.fan().ray_matrix() [ 1  1 -1 -1 -1 -1  1  1] [ 2 -1  1 -1 -1  1 -1  1] [ 3  1  1  1 -1 -1 -1 -1] sage: Cube_nonpolyhedral.fan().rays() N( 1,  2,  3), N( 1, -1,  1), N(-1,  1,  1), N(-1, -1,  1), N(-1, -1, -1), N(-1,  1, -1), N( 1, -1, -1), N( 1,  1, -1) in 3-d lattice N sage: Cube_nonpolyhedral.gens() (z0, z1, z2, z3, z4, z5, z6, z7) """ sage: X_2 = toric_varieties.Cube_deformation(2) sage: X_2 3-d toric variety covered by 6 affine patches sage: X_2.fan().ray_matrix() [ 1  1 -1 -1 -1 -1  1  1] [ 1 -1  1 -1 -1  1 -1  1] [ 5  1  1  1 -1 -1 -1 -1] sage: X_2.fan().rays() N( 1,  1,  5), N( 1, -1,  1), N(-1,  1,  1), N(-1, -1,  1), N(-1, -1, -1), N(-1,  1, -1), N( 1, -1, -1), N( 1,  1, -1) in 3-d lattice N sage: X_2.gens() (z0, z1, z2, z3, z4, z5, z6, z7) EXAMPLES:: sage: X = toric_varieties.BCdlOG()      # long time (56s on sage.math, 2011) sage: X                                 # long time sage: X = toric_varieties.BCdlOG() sage: X 5-d CPR-Fano toric variety covered by 54 affine patches sage: X.fan().ray_matrix()              # long time [-1  0  0  0  0  0  0  0  0  0  0  0  1] [ 0 -1  0  0  0  0  0  0  0  0  1  1  0] [ 0  0 -1 -1  0  0  0  1  2  1  2  3  4] [ 2  2  2  1 -1  0  2  2  2  1  2  2  2] [ 3  3  3  2  0 -1  3  3  3  1  3  3  3] sage: X.gens()                          # long time sage: X.fan().rays() N(-1,  0,  0,  2,  3), N( 0, -1,  0,  2,  3), N( 0,  0, -1,  2,  3), N( 0,  0, -1,  1,  2), N( 0,  0,  0, -1,  0), N( 0,  0,  0,  0, -1), N( 0,  0,  0,  2,  3), N( 0,  0,  1,  2,  3), N( 0,  0,  2,  2,  3), N( 0,  0,  1,  1,  1), N( 0,  1,  2,  2,  3), N( 0,  1,  3,  2,  3), N( 1,  0,  4,  2,  3) in 5-d lattice N sage: X.gens() (v1, v2, c1, c2, v4, v5, b, e1, e2, e3, f, g, v6) REFERENCES: sage: base = toric_varieties.BCdlOG_base() sage: base 3-d toric variety covered by 10 affine patches sage: base.fan().ray_matrix() [-1  0  0  0  0  0  1] [ 0 -1  0  0  1  1  0] [ 0  0 -1  1  2  3  4] sage: base.fan().rays() N(-1,  0,  0), N( 0, -1,  0), N( 0,  0, -1), N( 0,  0,  1), N( 0,  1,  2), N( 0,  1,  3), N( 1,  0,  4) in 3-d lattice N sage: base.gens() (d4, d3, r2, r1, d2, u, d1) """ sage: P2_112 = toric_varieties.P2_112() sage: P2_112 2-d CPR-Fano toric variety covered by 3 affine patches sage: P2_112.fan().ray_matrix() [ 1  0 -1] [ 0  1 -2] sage: P2_112.fan().rays() N( 1,  0), N( 0,  1), N(-1, -2) in 2-d lattice N sage: P2_112.gens() (z0, z1, z2) """ sage: P2_123 = toric_varieties.P2_123() sage: P2_123 2-d CPR-Fano toric variety covered by 3 affine patches sage: P2_123.fan().ray_matrix() [ 1  0 -2] [ 0  1 -3] sage: P2_123.fan().rays() N( 1,  0), N( 0,  1), N(-2, -3) in 2-d lattice N sage: P2_123.gens() (z0, z1, z2) """ sage: P4_11169 = toric_varieties.P4_11169() sage: P4_11169 4-d CPR-Fano toric variety covered by 5 affine patches sage: P4_11169.fan().ray_matrix() [ 1  0  0  0 -9] [ 0  1  0  0 -6] [ 0  0  1  0 -1] [ 0  0  0  1 -1] sage: P4_11169.fan().rays() N( 1,  0,  0,  0), N( 0,  1,  0,  0), N( 0,  0,  1,  0), N( 0,  0,  0,  1), N(-9, -6, -1, -1) in 4-d lattice N sage: P4_11169.gens() (z0, z1, z2, z3, z4) """ EXAMPLES:: sage: P4_11169_resolved = toric_varieties.P4_11169_resolved()  # long time (2s on sage.math, 2011) sage: P4_11169_resolved                      # long time sage: P4_11169_resolved = toric_varieties.P4_11169_resolved() sage: P4_11169_resolved 4-d CPR-Fano toric variety covered by 9 affine patches sage: P4_11169_resolved.fan().ray_matrix()   # long time [ 1  0  0  0 -9 -3] [ 0  1  0  0 -6 -2] [ 0  0  1  0 -1  0] [ 0  0  0  1 -1  0] sage: P4_11169_resolved.gens()               # long time sage: P4_11169_resolved.fan().rays() N( 1,  0,  0,  0), N( 0,  1,  0,  0), N( 0,  0,  1,  0), N( 0,  0,  0,  1), N(-9, -6, -1, -1), N(-3, -2,  0,  0) in 4-d lattice N sage: P4_11169_resolved.gens() (z0, z1, z2, z3, z4, z5) """ return self._make_CPRFanoToricVariety('P4_11169_resolved', names) sage: P4_11133 = toric_varieties.P4_11133() sage: P4_11133 4-d CPR-Fano toric variety covered by 5 affine patches sage: P4_11133.fan().ray_matrix() [ 1  0  0  0 -3] [ 0  1  0  0 -3] [ 0  0  1  0 -1] [ 0  0  0  1 -1] sage: P4_11133.fan().rays() N( 1,  0,  0,  0), N( 0,  1,  0,  0), N( 0,  0,  1,  0), N( 0,  0,  0,  1), N(-3, -3, -1, -1) in 4-d lattice N sage: P4_11133.gens() (z0, z1, z2, z3, z4) """ sage: P4_11133_resolved = toric_varieties.P4_11133_resolved() sage: P4_11133_resolved 4-d CPR-Fano toric variety covered by 9 affine patches sage: P4_11133_resolved.fan().ray_matrix() [ 1  0  0  0 -3 -1] [ 0  1  0  0 -3 -1] [ 0  0  1  0 -1  0] [ 0  0  0  1 -1  0] sage: P4_11133_resolved.fan().rays() N( 1,  0,  0,  0), N( 0,  1,  0,  0), N( 0,  0,  1,  0), N( 0,  0,  0,  1), N(-3, -3, -1, -1), N(-1, -1,  0,  0) in 4-d lattice N sage: P4_11133_resolved.gens() (z0, z1, z2, z3, z4, z5) """
• ## sage/schemes/toric/morphism.py

diff --git a/sage/schemes/toric/morphism.py b/sage/schemes/toric/morphism.py
 a sage: A2_Z2 = toric_varieties.A2_Z2() sage: A2_Z2.fan().rays() (N(1, 0), N(1, 2)) N(1, 0), N(1, 2) in 2-d lattice N sage: O2_P1 = A2_Z2.resolve(new_rays=[(1,1)]) sage: blowup = O2_P1.hom(identity_matrix(2), A2_Z2) sage: blowup.as_polynomial_map() for rho, x in zip(phi.domain_fan(1), R.gens()): ray = rho.ray(0) sigma = phi.image_cone(rho) degrees = sigma.ray_matrix().solve_right(phi(ray)) degrees = sigma.rays().matrix().solve_left(phi(ray)) for i, d in zip(sigma.ambient_ray_indices(), degrees): try: d = ZZ(d)
• ## sage/schemes/toric/variety.py

diff --git a/sage/schemes/toric/variety.py b/sage/schemes/toric/variety.py
 a sage: P1xP1 = ToricVariety(fan) sage: P1xP1 2-d toric variety covered by 4 affine patches sage: P1xP1.fan().ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: P1xP1.fan().rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: P1xP1.gens() (z0, z1, z2, z3) sage: patch = P1xP1.affine_patch(2) sage: patch 2-d affine toric variety sage: patch.fan().ray_matrix() [1 0] [0 1] sage: patch.fan().rays() N(1, 0), N(0, 1) in 2-d lattice N sage: patch.embedding_morphism() Scheme morphism: From: 2-d affine toric variety sage: P1xP1.is_smooth() True sage: TV = ToricVariety(NormalFan(diamond)) sage: TV.fan().ray_matrix() [-1  1 -1  1] [ 1  1 -1 -1] sage: TV.fan().rays() N(-1,  1), N( 1,  1), N(-1, -1), N( 1, -1) in 2-d lattice N sage: TV.is_orbifold() True sage: TV.is_smooth() In higher dimensions worse things can happen:: sage: TV3 = ToricVariety(NormalFan(lattice_polytope.octahedron(3))) sage: TV3.fan().ray_matrix() [-1  1 -1  1 -1  1 -1  1] [-1 -1  1  1 -1 -1  1  1] [ 1  1  1  1 -1 -1 -1 -1] sage: TV3.fan().rays() N(-1, -1,  1), N( 1, -1,  1), N(-1,  1,  1), N( 1,  1,  1), N(-1, -1, -1), N( 1, -1, -1), N(-1,  1, -1), N( 1,  1, -1) in 3-d lattice N sage: TV3.is_orbifold() False We will create the product of two projective lines:: sage: fan = FaceFan(lattice_polytope.octahedron(2)) sage: fan.ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: fan.rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: P1xP1 = ToricVariety(fan) sage: P1xP1.gens() (z0, z1, z2, z3) (x, y) for one and (s, t) for the other:: sage: fan = FaceFan(lattice_polytope.octahedron(2)) sage: fan.ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: fan.rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: P1xP1 = ToricVariety(fan, "x s y t") sage: P1xP1.inject_variables() Defining x, s, y, t (x, y) for one and (s, t) for the other:: sage: fan = FaceFan(lattice_polytope.octahedron(2)) sage: fan.ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: fan.rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: P1xP1 = ToricVariety(fan, "x s y t") sage: P1xP1.inject_variables() Defining x, s, y, t if '_homogeneous_degrees_group' not in self.__dict__: fan = self.fan() from sage.modules.free_module import FreeModule degrees_group = FreeModule(ZZ, fan.nrays()).quotient(fan.ray_matrix().rows()) degrees_group = FreeModule(ZZ, fan.nrays()).quotient( fan.rays().matrix().columns()) self._homogeneous_degrees_group = degrees_group degrees_group = self._homogeneous_degrees_group S = self.coordinate_ring() sage: Kc 2-d cone in 2-d lattice sage: Kc.rays() (Divisor class [0, 1], Divisor class [1, 0]) Divisor class [0, 1], Divisor class [1, 0] in Basis lattice of The toric rational divisor class group of a 2-d CPR-Fano toric variety covered by 4 affine patches sage: [ divisor_class.lift() for divisor_class in Kc.rays() ] [V(x), V(s)] sage: Kc.lattice() return self._Kaehler_cone def Mori_cone(self): """ r""" Returns the Mori cone of self. OUTPUT: sage: P4_11169.Mori_cone() 2-d cone in 7-d lattice sage: P4_11169.Mori_cone().rays() ((0, 0, 1, 1, 1, -3, 0), (3, 2, 0, 0, 0, 1, -6)) (0, 0, 1, 1, 1, -3,  0), (3, 2, 0, 0, 0,  1, -6) in Ambient free module of rank 7 over the principal ideal domain Integer Ring """ if "_Mori_cone" not in self.__dict__: # Ideally, self.Kaehler_cone().dual() should be it, but sage: P1xP1 = P1.cartesian_product(P1); P1xP1 2-d toric variety covered by 4 affine patches sage: P1xP1.fan().rays() (N+N(-1, 0), N+N(1, 0), N+N(0, -1), N+N(0, 1)) N+N(-1,  0), N+N( 1,  0), N+N( 0, -1), N+N( 0,  1) in 2-d lattice N+N """ return ToricVariety(self.fan().cartesian_product(other.fan()), coordinate_names, coordinate_indices, sage: TV_res = TV.resolve(new_rays=[(0,1)]) sage: TV_res.is_smooth() True sage: TV_res.fan().ray_matrix() [ 1 -1  0] [ 1  1  1] sage: TV_res.fan().rays() N( 1, 1), N(-1, 1), N( 0, 1) in 2-d lattice N sage: [cone.ambient_ray_indices() for cone in TV_res.fan()] [(0, 2), (1, 2)] with coordinates (x, y) for one and (s, t)` for the other:: sage: fan = FaceFan(lattice_polytope.octahedron(2)) sage: fan.ray_matrix() [ 1  0 -1  0] [ 0  1  0 -1] sage: fan.rays() N( 1,  0), N( 0,  1), N(-1,  0), N( 0, -1) in 2-d lattice N sage: P1xP1 = ToricVariety(fan, "x s y t") sage: P1xP1.inject_variables() Defining x, s, y, t basis = dual.Hilbert_basis() N = len(basis) names = normalize_names(names, N, DEFAULT_PREFIX) A = matrix(ZZ,basis).transpose() A = basis.column_matrix() IA = ToricIdeal(A, names, base_ring=self.base_ring()) return (IA.ring(), IA, dual) elif is_Cone(x): cone = fan.embed(x) assert cone.ambient() is fan mult = cone.ray_matrix().index_in_saturation() mult = cone.rays().column_matrix().index_in_saturation() x = prod((self.cover_ring().gen(i) for i in cone.ambient_ray_indices()), z=self.cover_ring().one()) * mult else: