### Navigation

- index
- modules |
- next |
- previous |
- Combinatorial Geometry »

# Convex rational polyhedral cones

This module was designed as a part of framework for toric varieties (`variety`, `fano_variety`). While the emphasis is on strictly convex cones, non-strictly convex cones are supported as well. Work with distinct lattices (in the sense of discrete subgroups spanning vector spaces) is supported. The default lattice is `ToricLattice` \(N\) of the appropriate dimension. The only case when you must specify lattice explicitly is creation of a 0-dimensional cone, where dimension of the ambient space cannot be guessed.

AUTHORS:

- Andrey Novoseltsev (2010-05-13): initial version.
- Andrey Novoseltsev (2010-06-17): substantial improvement during review by Volker Braun.
- Volker Braun (2010-06-21): various spanned/quotient/dual lattice computations added.
- Volker Braun (2010-12-28): Hilbert basis for cones.
- Andrey Novoseltsev (2012-02-23): switch to PointCollection container.

EXAMPLES:

Use `Cone()` to construct cones:

    sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
    sage: halfspace = Cone([(1,0,0), (0,1,0), (-1,-1,0), (0,0,1)])
    sage: positive_xy = Cone([(1,0,0), (0,1,0)])
    sage: four_rays = Cone([(1,1,1), (1,-1,1), (-1,-1,1), (-1,1,1)])

For all of the cones above we have provided primitive generating rays, but in fact this is not necessary - a cone can be constructed from any collection of rays (from the same space, of course). If there are non-primitive (or even non-integral) rays, they will be replaced with primitive ones. If there are extra rays, they will be discarded. Of course, this means that `Cone()` has to do some work before actually constructing the cone and sometimes it is not desirable, if you know for sure that your input is already “good”. In this case you can use options `check=False` to force `Cone()` to use exactly the directions that you have specified and `normalize=False` to force it to use exactly the rays that you have specified. However, it is better not to use these possibilities without necessity, since cones are assumed to be represented by a minimal set of primitive generating rays. See `Cone()` for further documentation on construction.

Once you have a cone, you can perform numerous operations on it. The most important ones are, probably, ray accessing methods:

    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(0, -1, 0), N(0, 0, 1), N(0, 1, 0), N(1, 0, 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)

The method `rays()` returns a `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 `output_format()` of all point collections to be such a matrix.

If you want to do something with each ray of a cone, you can write

    sage: for ray in positive_xy: print ray
    N(1, 0, 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: positive_xy.dim()
    2
    sage: positive_xy.lattice_dim()
    3

You also may be interested in this dimension:

    sage: dim(positive_xy.linear_subspace())
    0
    sage: dim(halfspace.linear_subspace())
    2

Or, perhaps, all you care about is whether it is zero or not:

    sage: positive_xy.is_strictly_convex()
    True
    sage: halfspace.is_strictly_convex()
    False

You can also perform these checks:

    sage: positive_xy.is_simplicial()
    True
    sage: four_rays.is_simplicial()
    False
    sage: positive_xy.is_smooth()
    True

You can work with subcones that form faces of other cones:

    sage: face = four_rays.faces(dim=2)[0]
    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)
    in 3-d lattice N
    sage: face.ambient_ray_indices()
    (2, 3)
    sage: four_rays.rays(face.ambient_ray_indices())
    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

    sage: L = four_rays.face_lattice()
    sage: map(len, L.level_sets())
    [1, 4, 4, 1]
    sage: face = L.level_sets()[2][0]
    sage: face.rays()
    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

The order of faces in level sets of the face lattice may differ from the order of faces returned by `faces()`. While the first order is random, the latter one ensures that one-dimensional faces are listed in the same order as generating rays.

When all the functionality provided by cones is not enough, you may want to check if you can do necessary things using polyhedra corresponding to cones:

    sage: four_rays.polyhedron()
    A 3-dimensional polyhedron in ZZ^3 defined as
    the convex hull of 1 vertex and 4 rays

And of course you are always welcome to suggest new features that should be added to cones!

REFERENCES:

[Fulton] | (1, 2, 3, 4, 5) Wiliam Fulton, “Introduction to Toric Varieties”, Princeton University Press

`sage.geometry.cone.``Cone`(rays, lattice=None, check=True, normalize=True)

  Construct a (not necessarily strictly) convex rational polyhedral cone.

  INPUT:

  - `rays` – a list of rays. Each ray should be given as a list or a vector convertible to the rational extension of the given `lattice`. May also be specified by a `Polyhedron_base` object;
  - `lattice` – `ToricLattice`, \(\ZZ^n\), or any other object that behaves like these. If not specified, an attempt will be made to determine an appropriate toric lattice automatically;
  - `check` – by default the input data will be checked for correctness (e.g. that all rays have the same number of components) and generating rays will be constructed from `rays`. If you know that the input is a minimal set of generators of a valid cone, you may significantly decrease construction time using `check=False` option;
  - `normalize` – you can further speed up construction using `normalize=False` option. In this case `rays` must be a list of immutable primitive rays in `lattice`. In general, you should not use this option, it is designed for code optimization and does not give as drastic improvement in speed as the previous one.

  OUTPUT:

  - convex rational polyhedral cone determined by `rays`.

  EXAMPLES:

  Let’s define a cone corresponding to the first quadrant of the plane (note, you can even mix objects of different types to represent rays, as long as you let this function to perform all the checks and necessary conversions!):

      sage: quadrant = Cone([(1,0), [0,1]])
      sage: quadrant
      2-d cone in 2-d lattice N
      sage: quadrant.rays()
      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)
      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)
      in 2-d lattice N

  Even worse things can happen with `normalize=False` option:

      sage: Cone([(1,0), (0,1)], check=False, normalize=False)
      Traceback (most recent call last):
      ...
      AttributeError: 'tuple' object has no attribute 'parent'

  You can construct different “not” cones: not full-dimensional, not strictly convex, not containing any rays:

      sage: one_dimensional_cone = Cone([(1,0)])
      sage: one_dimensional_cone.dim()
      1
      sage: half_plane = Cone([(1,0), (0,1), (-1,0)])
      sage: half_plane.rays()
      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:

      sage: origin = Cone([])
      Traceback (most recent call last):
      ...
      ValueError: lattice must be given explicitly if there are no rays!
      sage: origin = Cone([], lattice=ToricLattice(2))
      sage: origin.dim()
      0
      sage: origin.lattice_dim()
      2
      sage: origin.lattice()
      2-d lattice N

  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)
      in 3-d lattice L

  Or you can construct cones from rays of a particular lattice:

      sage: ray1 = L(1,0,0)
      sage: ray2 = L(1,1,1)
      sage: c2 = Cone([ray1, ray2])
      sage: c2.rays()
      L(1, 0, 0),
      L(1, 1, 1)
      in 3-d lattice L
      sage: c1 == c2
      True

  When the cone in question is not strictly convex, the standard form for the “generating rays” of the linear subspace is “basis vectors and their negatives”, as in the following example:

      sage: plane = Cone([(1,0), (0,1), (-1,-1)])
      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 `Polyhedron_base`:

      sage: p = plane.polyhedron()
      sage: Cone(p)
      2-d cone in 2-d lattice N
      sage: Cone(p) == plane
      True

  TESTS:

      sage: N = ToricLattice(2)
      sage: Nsub = N.span([ N(1,2) ])
      sage: Cone(Nsub.basis())
      1-d cone in Sublattice <N(1, 2)>
      sage: Cone([N(0)])
      0-d cone in 2-d lattice N

class `sage.geometry.cone.``ConvexRationalPolyhedralCone`(rays=None, lattice=None, ambient=None, ambient_ray_indices=None, PPL=None)

  Bases: `sage.geometry.cone.IntegralRayCollection`, `_abcoll.Container`

  Create a convex rational polyhedral cone.

  Warning

  This class does not perform any checks of correctness of input nor does it convert input into the standard representation. Use `Cone()` to construct cones.

  Cones are immutable, but they cache most of the returned values.

  INPUT:

  The input can be either:

  - `rays` – list of immutable primitive vectors in `lattice`;
  - `lattice` – `ToricLattice`, \(\ZZ^n\), or any other object that behaves like these. If `None`, it will be determined as `parent()` of the first ray. Of course, this cannot be done if there are no rays, so in this case you must give an appropriate `lattice` directly.

  or (these parameters must be given as keywords):

  - `ambient` – ambient structure of this cone, a bigger `cone` or a `fan`, this cone must be a face of `ambient`;
  - `ambient_ray_indices` – increasing list or tuple of integers, indices of rays of `ambient` generating this cone.

  In both cases, the following keyword parameter may be specified in addition:

  - `PPL` – either `None` (default) or a `C_Polyhedron` representing the cone. This serves only to cache the polyhedral data if you know it already. The polyhedron will be set immutable.

  OUTPUT:

  - convex rational polyhedral cone.

  Note

  Every cone has its ambient structure. If it was not specified, it is this cone itself.

  `Hilbert_basis`()

    Return the Hilbert basis of the cone.

    Given a strictly convex cone \(C\subset \RR^d\), the Hilbert basis of \(C\) is the set of all irreducible elements in the semigroup \(C\cap \ZZ^d\). It is the unique minimal generating set over \(\ZZ\) for the integral points \(C\cap \ZZ^d\).

    If the cone \(C\) is not strictly convex, this method finds the (unique) minimial set of lattice points that need to be added to the defining rays of the cone to generate the whole semigroup \(C\cap \ZZ^d\). But because the rays of the cone are not unique nor necessarily minimal in this case, neither is the returned generating set (consisting of the rays plus additional generators).

    See also `semigroup_generators()` if you are not interested in a minimal set of generators.

    OUTPUT:

    - a `PointCollection`. The rays of `self` are the first `self.nrays()` entries.

    EXAMPLES:

    The following command ensures that the output ordering in the examples below is independent of TOPCOM, you don’t have to use it:

        sage: PointConfiguration.set_engine('internal')

    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)
        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)
        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)
        in 4-d lattice M

    Not a strictly convex cone:

        sage: wedge = Cone([ (1,0,0), (1,2,0), (0,0,1), (0,0,-1) ])
        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)
        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)
        in 3-d lattice N

    ALGORITHM:

    The primal Normaliz algorithm, see [Normaliz].

    REFERENCES:

    [Normaliz] | (1, 2) Winfried Bruns, Bogdan Ichim, and Christof Soeger: Normaliz. http://www.mathematik.uni-osnabrueck.de/normaliz/

  `Hilbert_coefficients`(point)

    Return the expansion coefficients of `point` with respect to `Hilbert_basis()`.

    INPUT:

    - `point` – a `lattice()` point in the cone, or something that can be converted to a point. For example, a list or tuple of integers.

    OUTPUT:

    A \(\ZZ\)-vector of length `len(self.Hilbert_basis())` with nonnegative components.

    Note

    Since the Hilbert basis elements are not necessarily linearly independent, the expansion coefficients are not unique. However, this method will always return the same expansion coefficients when invoked with the same argument.

    EXAMPLES:

        sage: cone = Cone([(1,0),(0,1)])
        sage: cone.rays()
        N(1, 0),
        N(0, 1)
        in 2-d lattice N
        sage: cone.Hilbert_coefficients([3,2])
        (3, 2)

    A more complicated example:

        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)
        in 2-d lattice N
        sage: cone.Hilbert_coefficients( N(1,1) )
        (0, 0, 1)

    The cone need not be strictly convex:

        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)
        in 3-d lattice N
        sage: cone.Hilbert_coefficients( N(1,1,3) )
        (0, 0, 3, 0, 1)

  `adjacent`()

    Return faces adjacent to `self` in the ambient face lattice.

    Two distinct faces \(F_1\) and \(F_2\) of the same face lattice are adjacent if all of the following conditions hold:

    - \(F_1\) and \(F_2\) have the same dimension \(d\);
    - \(F_1\) and \(F_2\) share a facet of dimension \(d-1\);
    - \(F_1\) and \(F_2\) are facets of some face of dimension \(d+1\), unless \(d\) is the dimension of the ambient structure.

    OUTPUT:

    - `tuple` of `cones`.

    EXAMPLES:

        sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
        sage: octant.adjacent()
        ()
        sage: one_face = octant.faces(1)[0]
        sage: len(one_face.adjacent())
        2
        sage: one_face.adjacent()[1]
        1-d face of 3-d cone in 3-d lattice N

    Things are a little bit subtle with fans, as we illustrate below.

    First, we create a fan from two cones in the plane:

        sage: fan = Fan(cones=[(0,1), (1,2)],
        ...             rays=[(1,0), (0,1), (-1,0)])
        sage: cone = fan.generating_cone(0)
        sage: len(cone.adjacent())
        1

    The second generating cone is adjacent to this one. Now we create the same fan, but embedded into the 3-dimensional space:

        sage: fan = Fan(cones=[(0,1), (1,2)],
        ...             rays=[(1,0,0), (0,1,0), (-1,0,0)])
        sage: cone = fan.generating_cone(0)
        sage: len(cone.adjacent())
        1

    The result is as before, since we still have:

        sage: fan.dim()
        2

    Now we add another cone to make the fan 3-dimensional:

        sage: fan = Fan(cones=[(0,1), (1,2), (3,)],
        ...             rays=[(1,0,0), (0,1,0), (-1,0,0), (0,0,1)])
        sage: cone = fan.generating_cone(0)
        sage: len(cone.adjacent())
        0

    Since now `cone` has smaller dimension than `fan`, it and its adjacent cones must be facets of a bigger one, but since `cone` in this example is generating, it is not contained in any other.

  `ambient`()

    Return the ambient structure of `self`.

    OUTPUT:

    - cone or fan containing `self` as a face.

    EXAMPLES:

        sage: cone = Cone([(1,2,3), (4,6,5), (9,8,7)])
        sage: cone.ambient()
        3-d cone in 3-d lattice N
        sage: cone.ambient() is cone
        True
        sage: face = cone.faces(1)[0]
        sage: face
        1-d face of 3-d cone in 3-d lattice N
        sage: face.ambient()
        3-d cone in 3-d lattice N
        sage: face.ambient() is cone
        True

  `ambient_ray_indices`()

    Return indices of rays of the ambient structure generating `self`.

    OUTPUT:

    - increasing `tuple` of integers.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: quadrant.ambient_ray_indices()
        (0, 1)
        sage: quadrant.facets()[1].ambient_ray_indices()
        (1,)

  `cartesian_product`(other, lattice=None)

    Return the Cartesian product of `self` with `other`.

    INPUT:

    - `other` – a `cone`;
    - `lattice` – (optional) the ambient lattice for the Cartesian product cone. By default, the direct sum of the ambient lattices of `self` and `other` is constructed.

    OUTPUT:

    - a `cone`.

    EXAMPLES:

        sage: c = Cone([(1,)])
        sage: c.cartesian_product(c)
        2-d cone in 2-d lattice N+N
        sage: _.rays()
        N+N(1, 0),
        N+N(0, 1)
        in 2-d lattice N+N

  `contains`(*args)

    Check if a given point is contained in `self`.

    INPUT:

    - anything. An attempt will be made to convert all arguments into a single element of the ambient space of `self`. If it fails, `False` will be returned.

    OUTPUT:

    - `True` if the given point is contained in `self`, `False` otherwise.

    EXAMPLES:

        sage: c = Cone([(1,0), (0,1)])
        sage: c.contains(c.lattice()(1,0))
        True
        sage: c.contains((1,0))
        True
        sage: c.contains((1,1))
        True
        sage: c.contains(1,1)
        True
        sage: c.contains((-1,0))
        False
        sage: c.contains(c.dual_lattice()(1,0)) #random output (warning)
        False
        sage: c.contains(c.dual_lattice()(1,0))
        False
        sage: c.contains(1)
        False
        sage: c.contains(1/2, sqrt(3))
        True
        sage: c.contains(-1/2, sqrt(3))
        False

  `dual`()

    Return the dual cone of `self`.

    OUTPUT:

    - `cone`.

    EXAMPLES:

        sage: cone = Cone([(1,0), (-1,3)])
        sage: cone.dual().rays()
        M(0, 1),
        M(3, 1)
        in 2-d lattice M

    Now let’s look at a more complicated case:

        sage: cone = Cone([(-2,-1,2), (4,1,0), (-4,-1,-5), (4,1,5)])
        sage: cone.is_strictly_convex()
        False
        sage: cone.dim()
        3
        sage: cone.dual().rays()
        M(7, -18, -2),
        M(1,  -4,  0)
        in 3-d lattice M
        sage: cone.dual().dual() is cone
        True

    We correctly handle the degenerate cases:

        sage: N = ToricLattice(2)
        sage: Cone([], lattice=N).dual().rays()  # empty cone
        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)
        in 2-d lattice M
        sage: Cone([(1,0),(-1,0)], lattice=N).dual().rays()  # line in 2d
        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(0, 1),
        M(1, 0)
        in 2-d lattice M
        sage: Cone([(1,0),(-1,0),(0,1)], lattice=N).dual().rays()  # half space
        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

  `embed`(cone)

    Return the cone equivalent to the given one, but sitting in `self` as a face.

    You may need to use this method before calling methods of `cone` that depend on the ambient structure, such as `ambient_ray_indices()` or `facet_of()`. The cone returned by this method will have `self` as ambient. If `cone` does not represent a valid cone of `self`, `ValueError` exception is raised.

    Note

    This method is very quick if `self` is already the ambient structure of `cone`, so you can use without extra checks and performance hit even if `cone` is likely to sit in `self` but in principle may not.

    INPUT:

    - `cone` – a `cone`.

    OUTPUT:

    - a `cone`, equivalent to `cone` but sitting inside `self`.

    EXAMPLES:

    Let’s take a 3-d cone on 4 rays:

        sage: c = Cone([(1,0,1), (0,1,1), (-1,0,1), (0,-1,1)])

    Then any ray generates a 1-d face of this cone, but if you construct such a face directly, it will not “sit” inside the cone:

        sage: ray = Cone([(0,-1,1)])
        sage: ray
        1-d cone in 3-d lattice N
        sage: ray.ambient_ray_indices()
        (0,)
        sage: ray.adjacent()
        ()
        sage: ray.ambient()
        1-d cone in 3-d lattice N

    If we want to operate with this ray as a face of the cone, we need to embed it first:

        sage: e_ray = c.embed(ray)
        sage: e_ray
        1-d face of 3-d cone in 3-d lattice N
        sage: e_ray.rays()
        N(0, -1, 1)
        in 3-d lattice N
        sage: e_ray is ray
        False
        sage: e_ray.is_equivalent(ray)
        True
        sage: e_ray.ambient_ray_indices()
        (3,)
        sage: e_ray.adjacent()
        (1-d face of 3-d cone in 3-d lattice N,
         1-d face of 3-d cone in 3-d lattice N)
        sage: e_ray.ambient()
        3-d cone in 3-d lattice N

    Not every cone can be embedded into a fixed ambient cone:

        sage: c.embed(Cone([(0,0,1)]))
        Traceback (most recent call last):
        ...
        ValueError: 1-d cone in 3-d lattice N is not a face
        of 3-d cone in 3-d lattice N!
        sage: c.embed(Cone([(1,0,1), (-1,0,1)]))
        Traceback (most recent call last):
        ...
        ValueError: 2-d cone in 3-d lattice N is not a face
        of 3-d cone in 3-d lattice N!

  `face_lattice`()

    Return the face lattice of `self`.

    This lattice will have the origin as the bottom (we do not include the empty set as a face) and this cone itself as the top.

    OUTPUT:

    - `finite poset` of `cones`.

    EXAMPLES:

    Let’s take a look at the face lattice of the first quadrant:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: L = quadrant.face_lattice()
        sage: L
        Finite poset containing 4 elements with distinguished linear extension

    To see all faces arranged by dimension, you can do this:

        sage: for level in L.level_sets(): print level
        [0-d face of 2-d cone in 2-d lattice N]
        [1-d face of 2-d cone in 2-d lattice N,
         1-d face of 2-d cone in 2-d lattice N]
        [2-d cone in 2-d lattice N]

    For a particular face you can look at its actual rays...

        sage: face = L.level_sets()[1][0]
        sage: face.rays()
        N(1, 0)
        in 2-d lattice N

    ... or you can see the index of the ray of the original cone that corresponds to the above one:

        sage: face.ambient_ray_indices()
        (0,)
        sage: quadrant.ray(0)
        N(1, 0)

    An alternative to extracting faces from the face lattice is to use `faces()` method:

        sage: face is quadrant.faces(dim=1)[0]
        True

    The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:

        sage: face = L.level_sets()[1][0]
        sage: D = L.hasse_diagram()
        sage: D.neighbors(face)
        [2-d cone in 2-d lattice N,
         0-d face of 2-d cone in 2-d lattice N]

    However, you can achieve some of this functionality using `facets()`, `facet_of()`, and `adjacent()` methods:

        sage: face = quadrant.faces(1)[0]
        sage: face
        1-d face of 2-d cone in 2-d lattice N
        sage: face.rays()
        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()
        (2-d cone in 2-d lattice N,)
        sage: face.adjacent()
        (1-d face of 2-d cone in 2-d lattice N,)
        sage: face.adjacent()[0].rays()
        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`:

        sage: supercone = Cone([(1,2,3,4), (5,6,7,8),
        ...                     (1,2,4,8), (1,3,9,7)])
        sage: supercone.face_lattice()
        Finite poset containing 16 elements with distinguished linear extension
        sage: supercone.face_lattice().top()
        4-d cone in 4-d lattice N
        sage: cone = supercone.facets()[0]
        sage: cone
        3-d face of 4-d cone in 4-d lattice N
        sage: cone.face_lattice()
        Finite poset containing 8 elements with distinguished linear extension
        sage: cone.face_lattice().bottom()
        0-d face of 4-d cone in 4-d lattice N
        sage: cone.face_lattice().top()
        3-d face of 4-d cone in 4-d lattice N
        sage: cone.face_lattice().top() == cone
        True

    TESTS:

        sage: C1 = Cone([(0,1)])
        sage: C2 = Cone([(0,1)])
        sage: C1 == C2
        True
        sage: C1 is C2
        False

    C1 and C2 are equal, but not identical. We currently want them to have non identical face lattices, even if the faces themselves are equal (see #10998):

        sage: C1.face_lattice() is C2.face_lattice()
        False

        sage: C1.facets()[0]
        0-d face of 1-d cone in 2-d lattice N
        sage: C2.facets()[0]
        0-d face of 1-d cone in 2-d lattice N

        sage: C1.facets()[0].ambient() is C1
        True
        sage: C2.facets()[0].ambient() is C1
        False
        sage: C2.facets()[0].ambient() is C2
        True

  `faces`(dim=None, codim=None)

    Return faces of `self` of specified (co)dimension.

    INPUT:

    - `dim` – integer, dimension of the requested faces;
    - `codim` – integer, codimension of the requested faces.

    Note

    You can specify at most one parameter. If you don’t give any, then all faces will be returned.

    OUTPUT:

    - if either `dim` or `codim` is given, the output will be a `tuple` of `cones`;
    - if neither `dim` nor `codim` is given, the output will be the `tuple` of tuples as above, giving faces of all existing dimensions. If you care about inclusion relations between faces, consider using `face_lattice()` or `adjacent()`, `facet_of()`, and `facets()`.

    EXAMPLES:

    Let’s take a look at the faces of the first quadrant:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: quadrant.faces()
        ((0-d face of 2-d cone in 2-d lattice N,),
         (1-d face of 2-d cone in 2-d lattice N,
          1-d face of 2-d cone in 2-d lattice N),
         (2-d cone in 2-d lattice N,))
        sage: quadrant.faces(dim=1)
        (1-d face of 2-d cone in 2-d lattice N,
         1-d face of 2-d cone in 2-d lattice N)
        sage: face = quadrant.faces(dim=1)[0]

    Now you can look at the actual rays of this face...

        sage: face.rays()
        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.ambient_ray_indices()
        (0,)
        sage: quadrant.ray(0)
        N(1, 0)

    Note that it is OK to ask for faces of too small or high dimension:

        sage: quadrant.faces(-1)
        ()
        sage: quadrant.faces(3)
        ()

    In the case of non-strictly convex cones even faces of small non-negative dimension may be missing:

        sage: halfplane = Cone([(1,0), (0,1), (-1,0)])
        sage: halfplane.faces(0)
        ()
        sage: halfplane.faces()
        ((1-d face of 2-d cone in 2-d lattice N,),
         (2-d cone in 2-d lattice N,))
        sage: plane = Cone([(1,0), (0,1), (-1,-1)])
        sage: plane.faces(1)
        ()
        sage: plane.faces()
        ((2-d cone in 2-d lattice N,),)

    TESTS:

    Now we check that “general” cones whose dimension is smaller than the dimension of the ambient space work as expected (see trac ticket #9188):

        sage: c = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3)])
        sage: c.faces()
        ((0-d face of 3-d cone in 4-d lattice N,),
         (1-d face of 3-d cone in 4-d lattice N,
          1-d face of 3-d cone in 4-d lattice N,
          1-d face of 3-d cone in 4-d lattice N),
         (2-d face of 3-d cone in 4-d lattice N,
          2-d face of 3-d cone in 4-d lattice N,
          2-d face of 3-d cone in 4-d lattice N),
         (3-d cone in 4-d lattice N,))

    We also ensure that a call to this function does not break `facets()` method (see trac ticket #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: 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: for f in cone.facets(): print f.rays()
        N(1, 1)
        in 2-d lattice N
        N(0, 1)
        in 2-d lattice N

  `facet_normals`()

    Return inward normals to facets of `self`.

    Note

    1. For a not full-dimensional cone facet normals will specify hyperplanes whose intersections with the space spanned by `self` give facets of `self`.
    2. For a not strictly convex cone facet normals will be orthogonal to the linear subspace of `self`, i.e. they always will be elements of the dual cone of `self`.
    3. The order of normals is random, but consistent with `facets()`.

    OUTPUT:

    - a `PointCollection`.

    If the ambient `lattice()` of `self` is a `toric lattice`, the facet nomals will be elements of the dual lattice. If it is a general lattice (like `ZZ^n`) that does not have a `dual()` method, the facet normals will be returned as integral vectors.

    EXAMPLES:

        sage: cone = Cone([(1,0), (-1,3)])
        sage: cone.facet_normals()
        M(0, 1),
        M(3, 1)
        in 2-d lattice M

    Now let’s look at a more complicated case:

        sage: cone = Cone([(-2,-1,2), (4,1,0), (-4,-1,-5), (4,1,5)])
        sage: cone.is_strictly_convex()
        False
        sage: cone.dim()
        3
        sage: cone.linear_subspace().dimension()
        1
        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)
        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, 1),
        ( 1, 0)
        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)
        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(0, 1),
        M(1, 0)
        in 2-d lattice M
        sage: Cone([(1,0),(-1,0),(0,1)], lattice=N).facet_normals()  # half space
        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

  `facet_of`()

    Return cones of the ambient face lattice having `self` as a facet.

    OUTPUT:

    - `tuple` of `cones`.

    EXAMPLES:

        sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
        sage: octant.facet_of()
        ()
        sage: one_face = octant.faces(1)[0]
        sage: len(one_face.facet_of())
        2
        sage: one_face.facet_of()[1]
        2-d face of 3-d cone in 3-d lattice N

    While fan is the top element of its own cone lattice, which is a variant of a face lattice, we do not refer to cones as its facets:

        sage: fan = Fan([octant])
        sage: fan.generating_cone(0).facet_of()
        ()

    Subcones of generating cones work as before:

        sage: one_cone = fan(1)[0]
        sage: len(one_cone.facet_of())
        2

  `facets`()

    Return facets (faces of codimension 1) of `self`.

    OUTPUT:

    - `tuple` of `cones`.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: quadrant.facets()
        (1-d face of 2-d cone in 2-d lattice N,
         1-d face of 2-d cone in 2-d lattice N)

  `interior_contains`(*args)

    Check if a given point is contained in the interior of `self`.

    For a cone of strictly lower-dimension than the ambient space, the interior is always empty. You probably want to use `relative_interior_contains()` in this case.

    INPUT:

    - anything. An attempt will be made to convert all arguments into a single element of the ambient space of `self`. If it fails, `False` will be returned.

    OUTPUT:

    - `True` if the given point is contained in the interior of `self`, `False` otherwise.

    EXAMPLES:

        sage: c = Cone([(1,0), (0,1)])
        sage: c.contains((1,1))
        True
        sage: c.interior_contains((1,1))
        True
        sage: c.contains((1,0))
        True
        sage: c.interior_contains((1,0))
        False

  `intersection`(other)

    Compute the intersection of two cones.

    INPUT:

    - `other` - `cone`.

    OUTPUT:

    - `cone`.

    Raises `ValueError` if the ambient space dimensions are not compatible.

    EXAMPLES:

        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)
        in 2-d lattice N

    It is OK to intersect cones living in sublattices of the same ambient lattice:

        sage: N = cone1.lattice()
        sage: Ns = N.submodule([(1,1)])
        sage: cone3 = Cone([(1,1)], lattice=Ns)
        sage: I = cone1.intersection(cone3)
        sage: I.rays()
        N(1, 1)
        in Sublattice <N(1, 1)>
        sage: I.lattice()
        Sublattice <N(1, 1)>

    But you cannot intersect cones from incompatible lattices without explicit conversion:

        sage: cone1.intersection(cone1.dual())
        Traceback (most recent call last):
        ...
        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)
        in 2-d lattice N

  `is_equivalent`(other)

    Check if `self` is “mathematically” the same as `other`.

    INPUT:

    - `other` - cone.

    OUTPUT:

    - `True` if `self` and `other` define the same cones as sets of points in the same lattice, `False` otherwise.

    There are three different equivalences between cones \(C_1\) and \(C_2\) in the same lattice:

    1. They have the same generating rays in the same order. This is tested by `C1 == C2`.
    2. They describe the same sets of points. This is tested by `C1.is_equivalent(C2)`.
    3. They are in the same orbit of \(GL(n,\ZZ)\) (and, therefore, correspond to isomorphic affine toric varieties). This is tested by `C1.is_isomorphic(C2)`.

    EXAMPLES:

        sage: cone1 = Cone([(1,0), (-1, 3)])
        sage: cone2 = Cone([(-1,3), (1, 0)])
        sage: cone1.rays()
        N( 1, 0),
        N(-1, 3)
        in 2-d lattice N
        sage: cone2.rays()
        N(-1, 3),
        N( 1, 0)
        in 2-d lattice N
        sage: cone1 == cone2
        False
        sage: cone1.is_equivalent(cone2)
        True

  `is_face_of`(cone)

    Check if `self` forms a face of another `cone`.

    INPUT:

    - `cone` – cone.

    OUTPUT:

    - `True` if `self` is a face of `cone`, `False` otherwise.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: cone1 = Cone([(1,0)])
        sage: cone2 = Cone([(1,2)])
        sage: quadrant.is_face_of(quadrant)
        True
        sage: cone1.is_face_of(quadrant)
        True
        sage: cone2.is_face_of(quadrant)
        False

    Being a face means more than just saturating a facet inequality:

        sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
        sage: cone = Cone([(2,1,0),(1,2,0)])
        sage: cone.is_face_of(octant)
        False

  `is_isomorphic`(other)

    Check if `self` is in the same \(GL(n, \ZZ)\)-orbit as `other`.

    INPUT:

    - `other` - cone.

    OUTPUT:

    - `True` if `self` and `other` are in the same \(GL(n, \ZZ)\)-orbit, `False` otherwise.

    There are three different equivalences between cones \(C_1\) and \(C_2\) in the same lattice:

    1. They have the same generating rays in the same order. This is tested by `C1 == C2`.
    2. They describe the same sets of points. This is tested by `C1.is_equivalent(C2)`.
    3. They are in the same orbit of \(GL(n,\ZZ)\) (and, therefore, correspond to isomorphic affine toric varieties). This is tested by `C1.is_isomorphic(C2)`.

    EXAMPLES:

        sage: cone1 = Cone([(1,0), (0, 3)])
        sage: m = matrix(ZZ, [(1, -5), (-1, 4)]) # a GL(2,ZZ)-matrix
        sage: cone2 = Cone([m*r for r in cone1.rays()])
        sage: cone1.is_isomorphic(cone2)
        True

        sage: cone1 = Cone([(1,0), (0, 3)])
        sage: cone2 = Cone([(-1,3), (1, 0)])
        sage: cone1.is_isomorphic(cone2)
        False

    TESTS:

        sage: from sage.geometry.cone import classify_cone_2d
        sage: classify_cone_2d(*cone1.rays())
        (1, 0)
        sage: classify_cone_2d(*cone2.rays())
        (3, 2)

  `is_simplicial`()

    Check if `self` is simplicial.

    A cone is called simplicial if primitive vectors along its generating rays form a part of a rational basis of the ambient space.

    OUTPUT:

    - `True` if `self` is simplicial, `False` otherwise.

    EXAMPLES:

        sage: cone1 = Cone([(1,0), (0, 3)])
        sage: cone2 = Cone([(1,0), (0, 3), (-1,-1)])
        sage: cone1.is_simplicial()
        True
        sage: cone2.is_simplicial()
        False

  `is_smooth`()

    Check if `self` is smooth.

    A cone is called smooth if primitive vectors along its generating rays form a part of an integral basis of the ambient space. Equivalently, they generate the whole lattice on the linear subspace spanned by the rays.

    OUTPUT:

    - `True` if `self` is smooth, `False` otherwise.

    EXAMPLES:

        sage: cone1 = Cone([(1,0), (0, 1)])
        sage: cone2 = Cone([(1,0), (-1, 3)])
        sage: cone1.is_smooth()
        True
        sage: cone2.is_smooth()
        False

    The following cones are the same up to a \(SL(2,\ZZ)\) coordinate transformation:

        sage: Cone([(1,0,0), (2,1,-1)]).is_smooth()
        True
        sage: Cone([(1,0,0), (2,1,1)]).is_smooth()
        True
        sage: Cone([(1,0,0), (2,1,2)]).is_smooth()
        True

  `is_strictly_convex`()

    Check if `self` is strictly convex.

    A cone is called strictly convex if it does not contain any lines.

    OUTPUT:

    - `True` if `self` is strictly convex, `False` otherwise.

    EXAMPLES:

        sage: cone1 = Cone([(1,0), (0, 1)])
        sage: cone2 = Cone([(1,0), (-1, 0)])
        sage: cone1.is_strictly_convex()
        True
        sage: cone2.is_strictly_convex()
        False

  `is_trivial`()

    Checks if the cone has no rays.

    OUTPUT:

    - `True` if the cone has no rays, `False` otherwise.

    EXAMPLES:

        sage: c0 = Cone([], lattice=ToricLattice(3))
        sage: c0.is_trivial()
        True
        sage: c0.nrays()
        0

  `lattice_polytope`()

    Return the lattice polytope associated to `self`.

    The vertices of this polytope are primitive vectors along the generating rays of `self` and the origin, if `self` is strictly convex. In this case the origin is the last vertex, so the \(i\)-th ray of the cone always corresponds to the \(i\)-th vertex of the polytope.

    See also `polyhedron()`.

    OUTPUT:

    - `LatticePolytope`.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: lp = quadrant.lattice_polytope()
        doctest:...: DeprecationWarning: lattice_polytope(...) is deprecated!
        See http://trac.sagemath.org/16180 for details.
        sage: lp
        2-d lattice polytope in 2-d lattice N
        sage: lp.vertices_pc()
        N(1, 0),
        N(0, 1),
        N(0, 0)
        in 2-d lattice N

        sage: line = Cone([(1,0), (-1,0)])
        sage: lp = line.lattice_polytope()
        sage: lp
        1-d lattice polytope in 2-d lattice N
        sage: lp.vertices_pc()
        N( 1, 0),
        N(-1, 0)
        in 2-d lattice N

  `line_set`()

    Return a set of lines generating the linear subspace of `self`.

    OUTPUT:

    - `frozenset` of primitive vectors in the lattice of `self` giving directions of lines that span the linear subspace of `self`. These lines are arbitrary, but fixed. See also `lines()`.

    EXAMPLES:

        sage: halfplane = Cone([(1,0), (0,1), (-1,0)])
        sage: halfplane.line_set()
        doctest:...: DeprecationWarning: line_set(...) is deprecated, please use lines().set() instead!
        See http://trac.sagemath.org/12544 for details.
        frozenset({N(1, 0)})
        sage: fullplane = Cone([(1,0), (0,1), (-1,-1)])
        sage: fullplane.line_set()
        frozenset({N(0, 1), N(1, 0)})

  `linear_subspace`()

    Return the largest linear subspace contained inside of `self`.

    OUTPUT:

    - subspace of the ambient space of `self`.

    EXAMPLES:

        sage: halfplane = Cone([(1,0), (0,1), (-1,0)])
        sage: halfplane.linear_subspace()
        Vector space of degree 2 and dimension 1 over Rational Field
        Basis matrix:
        [1 0]

  `lines`()

    Return lines generating the linear subspace of `self`.

    OUTPUT:

    - `tuple` of primitive vectors in the lattice of `self` giving directions of lines that span the linear subspace of `self`. These lines are arbitrary, but fixed. If you do not care about the order, see also `line_set()`.

    EXAMPLES:

        sage: halfplane = Cone([(1,0), (0,1), (-1,0)])
        sage: halfplane.lines()
        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)
        in 2-d lattice N

  `orthogonal_sublattice`(*args, **kwds)

    The sublattice (in the dual lattice) orthogonal to the sublattice spanned by the cone.

    Let \(M=\) `self.dual_lattice()` be the lattice dual to the ambient lattice of the given cone \(\sigma\). Then, in the notation of [Fulton], this method returns the sublattice

    \[M(\sigma) \stackrel{\text{def}}{=} \sigma^\perp \cap M \subset M\]

    INPUT:

    - either nothing or something that can be turned into an element of this lattice.

    OUTPUT:

    - if no arguments were given, a `toric sublattice`, otherwise the corresponding element of it.

    EXAMPLES:

        sage: c = Cone([(1,1,1), (1,-1,1), (-1,-1,1), (-1,1,1)])
        sage: c.orthogonal_sublattice()
        Sublattice <>
        sage: c12 = Cone([(1,1,1), (1,-1,1)])
        sage: c12.sublattice()
        Sublattice <N(1, -1, 1), N(0, 1, 0)>
        sage: c12.orthogonal_sublattice()
        Sublattice <M(1, 0, -1)>

  `plot`(**options)

    Plot `self`.

    INPUT:

    - any options for toric plots (see `toric_plotter.options`), none are mandatory.

    OUTPUT:

    - a plot.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: quadrant.plot()
        Graphics object consisting of 9 graphics primitives

  `polyhedron`()

    Return the polyhedron associated to `self`.

    Mathematically this polyhedron is the same as `self`.

    OUTPUT:

    - `Polyhedron_base`.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: quadrant.polyhedron()
        A 2-dimensional polyhedron in ZZ^2 defined as the convex hull
        of 1 vertex and 2 rays
        sage: line = Cone([(1,0), (-1,0)])
        sage: line.polyhedron()
        A 1-dimensional polyhedron in ZZ^2 defined as the convex hull
        of 1 vertex and 1 line

    Here is an example of a trivial cone (see trac ticket #10237):

        sage: origin = Cone([], lattice=ZZ^2)
        sage: origin.polyhedron()
        A 0-dimensional polyhedron in ZZ^2 defined as the convex hull
        of 1 vertex

  `relative_interior_contains`(*args)

    Check if a given point is contained in the relative interior of `self`.

    For a full-dimensional cone the relative interior is simply the interior, so this method will do the same check as `interior_contains()`. For a strictly lower-dimensional cone, the relative interior is the cone without its facets.

    INPUT:

    - anything. An attempt will be made to convert all arguments into a single element of the ambient space of `self`. If it fails, `False` will be returned.

    OUTPUT:

    - `True` if the given point is contained in the relative interior of `self`, `False` otherwise.

    EXAMPLES:

        sage: c = Cone([(1,0,0), (0,1,0)])
        sage: c.contains((1,1,0))
        True
        sage: c.relative_interior_contains((1,1,0))
        True
        sage: c.interior_contains((1,1,0))
        False
        sage: c.contains((1,0,0))
        True
        sage: c.relative_interior_contains((1,0,0))
        False
        sage: c.interior_contains((1,0,0))
        False

  `relative_orthogonal_quotient`(supercone)

    The quotient of the dual spanned lattice by the dual of the supercone’s spanned lattice.

    In the notation of [Fulton], if `supercone` = \(\rho > \sigma\) = `self` is a cone that contains \(\sigma\) as a face, then \(M(\rho)\) = `supercone.orthogonal_sublattice()` is a saturated sublattice of \(M(\sigma)\) = `self.orthogonal_sublattice()`. This method returns the quotient lattice. The lifts of the quotient generators are \(\dim(\rho)-\dim(\sigma)\) linearly independent M-lattice lattice points that, together with \(M(\rho)\), generate \(M(\sigma)\).

    OUTPUT:

    - `toric lattice quotient`.

    If we call the output `Mrho`, then

    > - `Mrho.cover() == self.orthogonal_sublattice()`, and
    > - `Mrho.relations() == supercone.orthogonal_sublattice()`.

    Note

    - \(M(\sigma) / M(\rho)\) has no torsion since the sublattice \(M(\rho)\) is saturated.
    - In the codimension one case, (a lift of) the generator of \(M(\sigma) / M(\rho)\) is chosen to be positive on \(\sigma\).

    EXAMPLES:

        sage: rho = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3),(-1,1,1,3)])
        sage: rho.orthogonal_sublattice()
        Sublattice <M(0, 0, 3, -1)>
        sage: sigma = rho.facets()[1]
        sage: sigma.orthogonal_sublattice()
        Sublattice <M(0, 1, 1, 0), M(0, 0, 3, -1)>
        sage: sigma.is_face_of(rho)
        True
        sage: Q = sigma.relative_orthogonal_quotient(rho); Q
        1-d lattice, quotient
        of Sublattice <M(0, 1, 1, 0), M(0, 0, 3, -1)>
        by Sublattice <M(0, 0, 3, -1)>
        sage: Q.gens()
        (M[0, 1, 1, 0],)

    Different codimension:

        sage: rho = Cone([[1,-1,1,3],[-1,-1,1,3]])
        sage: sigma = rho.facets()[0]
        sage: sigma.orthogonal_sublattice()
        Sublattice <M(1, 0, 2, -1), M(0, 1, 1, 0), M(0, 0, 3, -1)>
        sage: rho.orthogonal_sublattice()
        Sublattice <M(0, 1, 1, 0), M(0, 0, 3, -1)>
        sage: sigma.relative_orthogonal_quotient(rho).gens()
        (M[-1, 0, -2, 1],)

    Sign choice in the codimension one case:

        sage: sigma1 = Cone([(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1)])  # 3d
        sage: sigma2 = Cone([(1, 1, -1), (1, 2, 3), (1, -1, 1), (1, -1, -1)])  # 3d
        sage: rho = sigma1.intersection(sigma2)
        sage: rho.relative_orthogonal_quotient(sigma1).gens()
        (M[-5, -2, 3],)
        sage: rho.relative_orthogonal_quotient(sigma2).gens()
        (M[5, 2, -3],)

  `relative_quotient`(subcone)

    The quotient of the spanned lattice by the lattice spanned by a subcone.

    In the notation of [Fulton], let \(N\) be the ambient lattice and \(N_\sigma\) the sublattice spanned by the given cone \(\sigma\). If \(\rho < \sigma\) is a subcone, then \(N_\rho\) = `rho.sublattice()` is a saturated sublattice of \(N_\sigma\) = `self.sublattice()`. This method returns the quotient lattice. The lifts of the quotient generators are \(\dim(\sigma)-\dim(\rho)\) linearly independent primitive lattice lattice points that, together with \(N_\rho\), generate \(N_\sigma\).

    OUTPUT:

    - `toric lattice quotient`.

    Note

    - The quotient \(N_\sigma / N_\rho\) of spanned sublattices has no torsion since the sublattice \(N_\rho\) is saturated.
    - In the codimension one case, the generator of \(N_\sigma / N_\rho\) is chosen to be in the same direction as the image \(\sigma / N_\rho\)

    EXAMPLES:

        sage: sigma = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3),(-1,1,1,3)])
        sage: rho   = Cone([(-1, -1, 1, 3), (-1, 1, 1, 3)])
        sage: sigma.sublattice()
        Sublattice <N(-1, -1, 1, 3), N(1, 0, 0, 0), N(1, 1, 0, 0)>
        sage: rho.sublattice()
        Sublattice <N(-1, 1, 1, 3), N(0, -1, 0, 0)>
        sage: sigma.relative_quotient(rho)
        1-d lattice, quotient
        of Sublattice <N(-1, -1, 1, 3), N(1, 0, 0, 0), N(1, 1, 0, 0)>
        by Sublattice <N(1, 0, -1, -3), N(0, 1, 0, 0)>
        sage: sigma.relative_quotient(rho).gens()
        (N[1, 1, 0, 0],)

    More complicated example:

        sage: rho = Cone([(1, 2, 3), (1, -1, 1)])
        sage: sigma = Cone([(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1)])
        sage: N_sigma = sigma.sublattice()
        sage: N_sigma
        Sublattice <N(-1, 1, 1), N(1, 2, 3), N(0, 1, 1)>
        sage: N_rho = rho.sublattice()
        sage: N_rho
        Sublattice <N(1, -1, 1), N(1, 2, 3)>
        sage: sigma.relative_quotient(rho).gens()
        (N[0, 1, 1],)
        sage: N = rho.lattice()
        sage: N_sigma == N.span(N_rho.gens() + tuple(q.lift()
        ...              for q in sigma.relative_quotient(rho).gens()))
        True

    Sign choice in the codimension one case:

        sage: sigma1 = Cone([(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1)])  # 3d
        sage: sigma2 = Cone([(1, 1, -1), (1, 2, 3), (1, -1, 1), (1, -1, -1)])  # 3d
        sage: rho = sigma1.intersection(sigma2)
        sage: rho.sublattice()
        Sublattice <N(1, -1, 1), N(1, 2, 3)>
        sage: sigma1.relative_quotient(rho)
        1-d lattice, quotient
        of Sublattice <N(-1, 1, 1), N(1, 2, 3), N(0, 1, 1)>
        by Sublattice <N(1, 2, 3), N(0, 3, 2)>
        sage: sigma1.relative_quotient(rho).gens()
        (N[0, 1, 1],)
        sage: sigma2.relative_quotient(rho).gens()
        (N[-1, 0, -2],)

  `semigroup_generators`()

    Return generators for the semigroup of lattice points of `self`.

    OUTPUT:

    - a `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 `Hilbert_basis()` for that.

    EXAMPLES:

    The following command ensures that the output ordering in the examples below is independent of TOPCOM, you don’t have to use it:

        sage: PointConfiguration.set_engine('internal')

    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)
        in 2-d lattice N

    A non-simplicial cone works, too:

        sage: cone = Cone([(3,0,-1), (1,-1,0), (0,1,0), (0,0,1)])
        sage: cone.semigroup_generators()
        (N(1, 0, 0), N(0, 0, 1), N(0, 1, 0), N(3, 0, -1), N(1, -1, 0))

    GAP’s toric package thinks this is challenging:

        sage: cone = Cone([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]).dual()
        sage: len( cone.semigroup_generators() )
        2806

    The cone need not be strictly convex:

        sage: halfplane = Cone([(1,0),(2,1),(-1,0)])
        sage: halfplane.semigroup_generators()
        (N(0, 1), N(1, 0), N(-1, 0))
        sage: line = Cone([(1,1,1),(-1,-1,-1)])
        sage: line.semigroup_generators()
        (N(1, 1, 1), N(-1, -1, -1))
        sage: wedge = Cone([ (1,0,0), (1,2,0), (0,0,1), (0,0,-1) ])
        sage: wedge.semigroup_generators()
        (N(1, 0, 0), N(1, 1, 0), N(1, 2, 0), N(0, 0, 1), N(0, 0, -1))

    Nor does it have to be full-dimensional (see 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)
        in 3-d lattice N

    Neither full-dimensional nor simplicial:

        sage: A = matrix([(1, 3, 0), (-1, 0, 1), (1, 1, -2), (15, -2, 0)])
        sage: A.elementary_divisors()
        [1, 1, 1, 0]
        sage: cone3d = Cone([(3,0,-1), (1,-1,0), (0,1,0), (0,0,1)])
        sage: rays = [ A*vector(v) for v in cone3d.rays() ]
        sage: gens = Cone(rays).semigroup_generators(); gens
        (N(1, -1, 1, 15), N(0, 1, -2, 0), N(-2, -1, 0, 17), N(3, -4, 5, 45), N(3, 0, 1, -2))
        sage: set(map(tuple,gens)) == set([ tuple(A*r) for r in cone3d.semigroup_generators() ])
        True

    TESTS:

        sage: len(Cone(identity_matrix(10).rows()).semigroup_generators())
        10

        sage: trivial_cone = Cone([], lattice=ToricLattice(3))
        sage: trivial_cone.semigroup_generators()
        Empty collection
        in 3-d lattice N

    ALGORITHM:

    If the cone is not simplicial, it is first triangulated. Each simplicial subcone has the integral points of the spaned parallelotope as generators. This is the first step of the primal Normaliz algorithm, see [Normaliz]. For each simplicial cone (of dimension \(d\)), the integral points of the open parallelotope

    \[\begin{split}par \langle x_1, \dots, x_d \rangle = \ZZ^n \cap \left\{ q_1 x_1 + \cdots +q_d x_d :~ 0 \leq q_i < 1 \right\}\end{split}\]

    are then computed [BrunsKoch].

    Finally, the the union of the generators of all simplicial subcones is returned.

    REFERENCES:

    [BrunsKoch] | W. Bruns and R. Koch, Computing the integral closure of an affine semigroup. Uni. Iaggelonicae Acta Math. 39, (2001), 59-70

  `strict_quotient`()

    Return the quotient of `self` by the linear subspace.

    We define the strict quotient of a cone to be the image of this cone in the quotient of the ambient space by the linear subspace of the cone, i.e. it is the “complementary part” to the linear subspace.

    OUTPUT:

    - cone.

    EXAMPLES:

        sage: halfplane = Cone([(1,0), (0,1), (-1,0)])
        sage: ssc = halfplane.strict_quotient()
        sage: ssc
        1-d cone in 1-d lattice N
        sage: ssc.rays()
        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

  `sublattice`(*args, **kwds)

    The sublattice spanned by the cone.

    Let \(\sigma\) be the given cone and \(N=\) `self.lattice()` the ambient lattice. Then, in the notation of [Fulton], this method returns the sublattice

    \[N_\sigma \stackrel{\text{def}}{=} \mathop{span}( N\cap \sigma )\]

    INPUT:

    - either nothing or something that can be turned into an element of this lattice.

    OUTPUT:

    - if no arguments were given, a `toric sublattice`, otherwise the corresponding element of it.

    Note

    - The sublattice spanned by the cone is the saturation of the sublattice generated by the rays of the cone.
    - See `sage.geometry.cone.IntegralRayCollection.ray_basis()` if you only need a \(\QQ\)-basis.
    - The returned lattice points are usually not rays of the cone. In fact, for a non-smooth cone the rays do not generate the sublattice \(N_\sigma\), but only a finite index sublattice.

    EXAMPLES:

        sage: cone = Cone([(1, 1, 1), (1, -1, 1), (-1, -1, 1), (-1, 1, 1)])
        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 <N(-1, -1, 1), N(1, 0, 0), N(1, 1, 0)>
        sage: matrix( cone.sublattice().gens() ).det()
        1

    Another example:

        sage: c = Cone([(1,2,3), (4,-5,1)])
        sage: c
        2-d cone in 3-d lattice N
        sage: c.rays()
        N(1,  2, 3),
        N(4, -5, 1)
        in 3-d lattice N
        sage: c.sublattice()
        Sublattice <N(1, 2, 3), N(4, -5, 1)>
        sage: c.sublattice(5, -3, 4)
        N(5, -3, 4)
        sage: c.sublattice(1, 0, 0)
        Traceback (most recent call last):
        ...
        TypeError: element (= [1, 0, 0]) is not in free module

  `sublattice_complement`(*args, **kwds)

    A complement of the sublattice spanned by the cone.

    In other words, `sublattice()` and `sublattice_complement()` together form a \(\ZZ\)-basis for the ambient `lattice()`.

    In the notation of [Fulton], let \(\sigma\) be the given cone and \(N=\) `self.lattice()` the ambient lattice. Then this method returns

    \[N(\sigma) \stackrel{\text{def}}{=} N / N_\sigma\]

    lifted (non-canonically) to a sublattice of \(N\).

    INPUT:

    - either nothing or something that can be turned into an element of this lattice.

    OUTPUT:

    - if no arguments were given, a `toric sublattice`, otherwise the corresponding element of it.

    EXAMPLES:

        sage: C2_Z2 = Cone([(1,0),(1,2)])     # C^2/Z_2
        sage: c1, c2 = C2_Z2.facets()
        sage: c2.sublattice()
        Sublattice <N(1, 2)>
        sage: c2.sublattice_complement()
        Sublattice <N(0, 1)>

    A more complicated example:

        sage: c = Cone([(1,2,3), (4,-5,1)])
        sage: c.sublattice()
        Sublattice <N(1, 2, 3), N(4, -5, 1)>
        sage: c.sublattice_complement()
        Sublattice <N(0, -6, -5)>
        sage: m = matrix( c.sublattice().gens() + c.sublattice_complement().gens() )
        sage: m
        [ 1  2  3]
        [ 4 -5  1]
        [ 0 -6 -5]
        sage: m.det()
        -1

  `sublattice_quotient`(*args, **kwds)

    The quotient of the ambient lattice by the sublattice spanned by the cone.

    INPUT:

    - either nothing or something that can be turned into an element of this lattice.

    OUTPUT:

    - if no arguments were given, a `quotient of a toric lattice`, otherwise the corresponding element of it.

    EXAMPLES:

        sage: C2_Z2 = Cone([(1,0),(1,2)])     # C^2/Z_2
        sage: c1, c2 = C2_Z2.facets()
        sage: c2.sublattice_quotient()
        1-d lattice, quotient of 2-d lattice N by Sublattice <N(1, 2)>
        sage: N = C2_Z2.lattice()
        sage: n = N(1,1)
        sage: n_bar = c2.sublattice_quotient(n); n_bar
        N[1, 1]
        sage: n_bar.lift()
        N(1, 1)
        sage: vector(n_bar)
        (-1)

class `sage.geometry.cone.``IntegralRayCollection`(rays, lattice)

  Bases: `sage.structure.sage_object.SageObject`, `_abcoll.Hashable`, `_abcoll.Iterable`

  Create a collection of integral rays.

  Warning

  No correctness check or normalization is performed on the input data. This class is designed for internal operations and you probably should not use it directly.

  This is a base class for `convex rational polyhedral cones` and `fans`.

  Ray collections are immutable, but they cache most of the returned values.

  INPUT:

  - `rays` – list of immutable vectors in `lattice`;
  - `lattice` – `ToricLattice`, \(\ZZ^n\), or any other object that behaves like these. If `None`, it will be determined as `parent()` of the first ray. Of course, this cannot be done if there are no rays, so in this case you must give an appropriate `lattice` directly. Note that `None` is not the default value - you always must give this argument explicitly, even if it is `None`.

  OUTPUT:

  - collection of given integral rays.
  `cartesian_product`(other, lattice=None)

    Return the Cartesian product of `self` with `other`.

    INPUT:

    - `other` – an `IntegralRayCollection`;
    - `lattice` – (optional) the ambient lattice for the result. By default, the direct sum of the ambient lattices of `self` and `other` is constructed.

    OUTPUT:

    - an `IntegralRayCollection`.

    By the Cartesian product of ray collections \((r_0, \dots, r_{n-1})\) and \((s_0, \dots, s_{m-1})\) we understand the ray collection of the form \(((r_0, 0), \dots, (r_{n-1}, 0), (0, s_0), \dots, (0, s_{m-1}))\), which is suitable for Cartesian products of cones and fans. The ray order is guaranteed to be as described.

    EXAMPLES:

        sage: c = Cone([(1,)])
        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)
        in 2-d lattice N+N

  `dim`()

    Return the dimension of the subspace spanned by rays of `self`.

    OUTPUT:

    - integer.

    EXAMPLES:

        sage: c = Cone([(1,0)])
        sage: c.lattice_dim()
        2
        sage: c.dim()
        1

  `dual_lattice`()

    Return the dual of the ambient lattice of `self`.

    OUTPUT:

    - lattice. If possible (that is, if `lattice()` has a `dual()` method), the dual lattice is returned. Otherwise, \(\ZZ^n\) is returned, where \(n\) is the dimension of `lattice()`.

    EXAMPLES:

        sage: c = Cone([(1,0)])
        sage: c.dual_lattice()
        2-d lattice M
        sage: Cone([], ZZ^3).dual_lattice()
        Ambient free module of rank 3
        over the principal ideal domain Integer Ring

  `lattice`()

    Return the ambient lattice of `self`.

    OUTPUT:

    - lattice.

    EXAMPLES:

        sage: c = Cone([(1,0)])
        sage: c.lattice()
        2-d lattice N
        sage: Cone([], ZZ^3).lattice()
        Ambient free module of rank 3
        over the principal ideal domain Integer Ring

  `lattice_dim`()

    Return the dimension of the ambient lattice of `self`.

    OUTPUT:

    - integer.

    EXAMPLES:

        sage: c = Cone([(1,0)])
        sage: c.lattice_dim()
        2
        sage: c.dim()
        1

  `nrays`()

    Return the number of rays of `self`.

    OUTPUT:

    - integer.

    EXAMPLES:

        sage: c = Cone([(1,0), (0,1)])
        sage: c.nrays()
        2

  `plot`(**options)

    Plot `self`.

    INPUT:

    - any options for toric plots (see `toric_plotter.options`), none are mandatory.

    OUTPUT:

    - a plot.

    EXAMPLES:

        sage: quadrant = Cone([(1,0), (0,1)])
        sage: quadrant.plot()
        Graphics object consisting of 9 graphics primitives

  `ray`(n)

    Return the `n`-th ray of `self`.

    INPUT:

    - `n` – integer, an index of a ray of `self`. Enumeration of rays starts with zero.

    OUTPUT:

    - ray, an element of the lattice of `self`.

    EXAMPLES:

        sage: c = Cone([(1,0), (0,1)])
        sage: c.ray(0)
        N(1, 0)

  `rays`(*args)

    Return (some of the) rays of `self`.

    INPUT:

    - `ray_list` – a list of integers, the indices of the requested rays. If not specified, all rays of `self` will be returned.

    OUTPUT:

    - a `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)
        in 2-d lattice N
        sage: c.rays([0, 2])
        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

`sage.geometry.cone.``classify_cone_2d`(ray0, ray1, check=True)

  Return \((d,k)\) classifying the lattice cone spanned by the two rays.

  INPUT:

  - `ray0`, `ray1` – two primitive integer vectors. The generators of the two rays generating the two-dimensional cone.
  - `check` – boolean (default: `True`). Whether to check the input rays for consistency.

  OUTPUT:

  A pair \((d,k)\) of integers classifying the cone up to \(GL(2, \ZZ)\) equivalence. See Proposition 10.1.1 of [CLS] for the definition. We return the unique \((d,k)\) with minmial \(k\), see Proposition 10.1.3 of [CLS].

  EXAMPLES:

      sage: ray0 = vector([1,0])
      sage: ray1 = vector([2,3])
      sage: from sage.geometry.cone import classify_cone_2d
      sage: classify_cone_2d(ray0, ray1)
      (3, 2)

      sage: ray0 = vector([2,4,5])
      sage: ray1 = vector([5,19,11])
      sage: classify_cone_2d(ray0, ray1)
      (3, 1)

      sage: m = matrix(ZZ, [(19, -14, -115), (-2, 5, 25), (43, -42, -298)])
      sage: m.det()   # check that it is in GL(3,ZZ)
      -1
      sage: classify_cone_2d(m*ray0, m*ray1)
      (3, 1)

  TESTS:

  Check using the connection between the Hilbert basis of the cone spanned by the two rays (in arbitrary dimension) and the Hirzebruch-Jung continued fraction expansion, see Chapter 10 of [CLS]

      sage: from sage.geometry.cone import normalize_rays
      sage: for i in range(10):
      ...       ray0 = random_vector(ZZ, 3)
      ...       ray1 = random_vector(ZZ, 3)
      ...       if ray0.is_zero() or ray1.is_zero(): continue
      ...       ray0, ray1 = normalize_rays([ray0, ray1], ZZ^3)
      ...       d, k = classify_cone_2d(ray0, ray1, check=True)
      ...       assert (d,k) == classify_cone_2d(ray1, ray0)
      ...       if d == 0: continue
      ...       frac = Hirzebruch_Jung_continued_fraction_list(k/d)
      ...       if len(frac)>100: continue   # avoid expensive computation
      ...       hilb = Cone([ray0, ray1]).Hilbert_basis()
      ...       assert len(hilb) == len(frac) + 1

`sage.geometry.cone.``is_Cone`(x)

  Check if `x` is a cone.

  INPUT:

  - `x` – anything.

  OUTPUT:

  - `True` if `x` is a cone and `False` otherwise.

  EXAMPLES:

      sage: from sage.geometry.cone import is_Cone
      sage: is_Cone(1)
      False
      sage: quadrant = Cone([(1,0), (0,1)])
      sage: quadrant
      2-d cone in 2-d lattice N
      sage: is_Cone(quadrant)
      True

`sage.geometry.cone.``normalize_rays`(rays, lattice)

  Normalize a list of rational rays: make them primitive and immutable.

  INPUT:

  - `rays` – list of rays which can be converted to the rational extension of `lattice`;
  - `lattice` – `ToricLattice`, \(\ZZ^n\), or any other object that behaves like these. If `None`, an attempt will be made to determine an appropriate toric lattice automatically.

  OUTPUT:

  - list of immutable primitive vectors of the `lattice` in the same directions as original `rays`.

  EXAMPLES:

      sage: from sage.geometry.cone import normalize_rays
      sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], None)
      [N(0, 1), N(0, 1), N(3, 2), N(3, 14)]
      sage: L = ToricLattice(2, "L")
      sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], L.dual())
      [L*(0, 1), L*(0, 1), L*(3, 2), L*(3, 14)]
      sage: ray_in_L = L(0,1)
      sage: normalize_rays([ray_in_L, (0, 2), (3, 2), (5/7, 10/3)], None)
      [L(0, 1), L(0, 1), L(3, 2), L(3, 14)]
      sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], ZZ^2)
      [(0, 1), (0, 1), (3, 2), (3, 14)]
      sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], ZZ^3)
      Traceback (most recent call last):
      ...
      TypeError: cannot convert (0, 1) to
      Vector space of dimension 3 over Rational Field!
      sage: normalize_rays([], ZZ^3)
      []

### Navigation

- index
- modules |
- next |
- previous |
- Combinatorial Geometry »