Toric lattices - Combinatorial and Discrete Geometry

Skip to content
Back to top
View this page
Edit this page

# Toric lattices

This module was designed as a part of the framework for toric varieties (`variety`, `fano_variety`).

All toric lattices are isomorphic to \(\ZZ^n\) for some \(n\), but will prevent you from doing “wrong” operations with objects from different lattices.

AUTHORS:

- Andrey Novoseltsev (2010-05-27): initial version.

- Andrey Novoseltsev (2010-07-30): sublattices and quotients.

EXAMPLES:

The simplest way to create a toric lattice is to specify its dimension only:

Sage

    sage: N = ToricLattice(3)
    sage: N
    3-d lattice N

Python

    >>> from sage.all import *
    >>> N = ToricLattice(Integer(3))
    >>> N
    3-d lattice N

While our lattice `N` is called exactly “N” it is a coincidence: all lattices are called “N” by default:

Sage

    sage: another_name = ToricLattice(3)
    sage: another_name
    3-d lattice N

[Python]

    >>> from sage.all import *
    >>> another_name = ToricLattice(Integer(3))
    >>> another_name
    3-d lattice N

If fact, the above lattice is exactly the same as before as an object in memory:

Sage

    sage: N is another_name
    True

Python

    >>> from sage.all import *
    >>> N is another_name
    True

There are actually four names associated to a toric lattice and they all must be the same for two lattices to coincide:

Sage

    sage: N, N.dual(), latex(N), latex(N.dual())
    (3-d lattice N, 3-d lattice M, N, M)

[Python]

    >>> from sage.all import *
    >>> N, N.dual(), latex(N), latex(N.dual())
    (3-d lattice N, 3-d lattice M, N, M)

Notice that the lattice dual to `N` is called “M” which is standard in toric geometry. This happens only if you allow completely automatic handling of names:

Sage

    sage: another_N = ToricLattice(3, "N")
    sage: another_N.dual()
    3-d lattice N*
    sage: N is another_N
    False

Python

    >>> from sage.all import *
    >>> another_N = ToricLattice(Integer(3), "N")
    >>> another_N.dual()
    3-d lattice N*
    >>> N is another_N
    False

What can you do with toric lattices? Well, their main purpose is to allow creation of elements of toric lattices:

Sage

    sage: n = N([1,2,3])
    sage: n
    N(1, 2, 3)
    sage: M = N.dual()
    sage: m = M(1,2,3)
    sage: m
    M(1, 2, 3)

[Python]

    >>> from sage.all import *
    >>> n = N([Integer(1),Integer(2),Integer(3)])
    >>> n
    N(1, 2, 3)
    >>> M = N.dual()
    >>> m = M(Integer(1),Integer(2),Integer(3))
    >>> m
    M(1, 2, 3)

Dual lattices can act on each other:

Sage

    sage: n * m
    14
    sage: m * n
    14

Python

    >>> from sage.all import *
    >>> n * m
    14
    >>> m * n
    14

You can also add elements of the same lattice or scale them:

Sage

    sage: 2 * n
    N(2, 4, 6)
    sage: n * 2
    N(2, 4, 6)
    sage: n + n
    N(2, 4, 6)

[Python]

    >>> from sage.all import *
    >>> Integer(2) * n
    N(2, 4, 6)
    >>> n * Integer(2)
    N(2, 4, 6)
    >>> n + n
    N(2, 4, 6)

However, you cannot “mix wrong lattices” in your expressions:

Sage

    sage: n + m
    Traceback (most recent call last):
    ...
    TypeError: unsupported operand parent(s) for +:
    '3-d lattice N' and '3-d lattice M'
    sage: n * n
    Traceback (most recent call last):
    ...
    TypeError: elements of the same toric lattice cannot be multiplied!
    sage: n == m
    False

Python

    >>> from sage.all import *
    >>> n + m
    Traceback (most recent call last):
    ...
    TypeError: unsupported operand parent(s) for +:
    '3-d lattice N' and '3-d lattice M'
    >>> n * n
    Traceback (most recent call last):
    ...
    TypeError: elements of the same toric lattice cannot be multiplied!
    >>> n == m
    False

Note that `n` and `m` are not equal to each other even though they are both “just (1,2,3).” Moreover, you cannot easily convert elements between toric lattices:

Sage

    sage: M(n)
    Traceback (most recent call last):
    ...
    TypeError: N(1, 2, 3) cannot be converted to 3-d lattice M!

[Python]

    >>> from sage.all import *
    >>> M(n)
    Traceback (most recent call last):
    ...
    TypeError: N(1, 2, 3) cannot be converted to 3-d lattice M!

If you really need to consider elements of one lattice as elements of another, you can either use intermediate conversion to “just a vector”:

Sage

    sage: ZZ3 = ZZ^3
    sage: n_in_M = M(ZZ3(n))
    sage: n_in_M
    M(1, 2, 3)
    sage: n == n_in_M
    False
    sage: n_in_M == m
    True

Python

    >>> from sage.all import *
    >>> ZZ3 = ZZ**Integer(3)
    >>> n_in_M = M(ZZ3(n))
    >>> n_in_M
    M(1, 2, 3)
    >>> n == n_in_M
    False
    >>> n_in_M == m
    True

Or you can create a homomorphism from one lattice to any other:

Sage

    sage: h = N.hom(identity_matrix(3), M)
    sage: h(n)
    M(1, 2, 3)

[Python]

    >>> from sage.all import *
    >>> h = N.hom(identity_matrix(Integer(3)), M)
    >>> h(n)
    M(1, 2, 3)

Warning

While integer vectors (elements of \(\ZZ^n\)) are printed as `(1,2,3)`, in the code `(1,2,3)` is a `tuple`, which has nothing to do neither with vectors, nor with toric lattices, so the following is probably not what you want while working with toric geometry objects:

Sage

    sage: (1,2,3) + (1,2,3)
    (1, 2, 3, 1, 2, 3)

Python

    >>> from sage.all import *
    >>> (Integer(1),Integer(2),Integer(3)) + (Integer(1),Integer(2),Integer(3))
    (1, 2, 3, 1, 2, 3)

Instead, use syntax like

Sage

    sage: N(1,2,3) + N(1,2,3)
    N(2, 4, 6)

[Python]

    >>> from sage.all import *
    >>> N(Integer(1),Integer(2),Integer(3)) + N(Integer(1),Integer(2),Integer(3))
    N(2, 4, 6)

class sage.geometry.toric_lattice.ToricLatticeFactory

  Bases: `UniqueFactory`

  Create a lattice for toric geometry objects.

  INPUT:

  - `rank` – nonnegative integer; the only mandatory parameter

  - `name` – string

  - `dual_name` – string

  - `latex_name` – string

  - `latex_dual_name` – string

  OUTPUT: lattice

  A toric lattice is uniquely determined by its rank and associated names. There are four such “associated names” whose meaning should be clear from the names of the corresponding parameters, but the choice of default values is a little bit involved. So here is the full description of the “naming algorithm”:

  1. If no names were given at all, then this lattice will be called “N” and the dual one “M”. These are the standard choices in toric geometry.

  2. If `name` was given and `dual_name` was not, then `dual_name` will be `name` followed by “*”.

  3. If LaTeX names were not given, they will coincide with the “usual” names, but if `dual_name` was constructed automatically, the trailing star will be typeset as a superscript.

  EXAMPLES:

  Let’s start with no names at all and see how automatic names are given:

  Sage

      sage: L1 = ToricLattice(3)
      sage: L1
      3-d lattice N
      sage: L1.dual()
      3-d lattice M

  Python

      >>> from sage.all import *
      >>> L1 = ToricLattice(Integer(3))
      >>> L1
      3-d lattice N
      >>> L1.dual()
      3-d lattice M

  If we give the name “N” explicitly, the dual lattice will be called “N*”:

  Sage

      sage: L2 = ToricLattice(3, "N")
      sage: L2
      3-d lattice N
      sage: L2.dual()
      3-d lattice N*

  [Python]

      >>> from sage.all import *
      >>> L2 = ToricLattice(Integer(3), "N")
      >>> L2
      3-d lattice N
      >>> L2.dual()
      3-d lattice N*

  However, we can give an explicit name for it too:

  Sage

      sage: L3 = ToricLattice(3, "N", "M")
      sage: L3
      3-d lattice N
      sage: L3.dual()
      3-d lattice M

  Python

      >>> from sage.all import *
      >>> L3 = ToricLattice(Integer(3), "N", "M")
      >>> L3
      3-d lattice N
      >>> L3.dual()
      3-d lattice M

  If you want, you may also give explicit LaTeX names:

  Sage

      sage: L4 = ToricLattice(3, "N", "M", r"\mathbb{N}", r"\mathbb{M}")
      sage: latex(L4)
      \mathbb{N}
      sage: latex(L4.dual())
      \mathbb{M}

  [Python]

      >>> from sage.all import *
      >>> L4 = ToricLattice(Integer(3), "N", "M", r"\mathbb{N}", r"\mathbb{M}")
      >>> latex(L4)
      \mathbb{N}
      >>> latex(L4.dual())
      \mathbb{M}

  While all four lattices above are called “N”, only two of them are equal (and are actually the same):

  Sage

      sage: L1 == L2
      False
      sage: L1 == L3
      True
      sage: L1 is L3
      True
      sage: L1 == L4
      False

  Python

      >>> from sage.all import *
      >>> L1 == L2
      False
      >>> L1 == L3
      True
      >>> L1 is L3
      True
      >>> L1 == L4
      False

  The reason for this is that `L2` and `L4` have different names either for dual lattices or for LaTeX typesetting.

  create_key(rank, name=None, dual_name=None, latex_name=None, latex_dual_name=None)

    Create a key that uniquely identifies this toric lattice.

    See `ToricLattice` for documentation.

    Warning

    You probably should not use this function directly.

  create_object(version, key)

    Create the toric lattice described by `key`.

    See `ToricLattice` for documentation.

    Warning

    You probably should not use this function directly.

class sage.geometry.toric_lattice.ToricLattice_ambient(rank, name, dual_name, latex_name, latex_dual_name)

  Bases: `ToricLattice_generic`, `FreeModule_ambient_pid`

  Create a toric lattice.

  See `ToricLattice` for documentation.

  Warning

  There should be only one toric lattice with the given rank and associated names. Using this class directly to create toric lattices may lead to unexpected results. Please, use `ToricLattice` to create toric lattices.

  Element

    alias of `ToricLatticeElement`

  ambient_module()

    Return the ambient module of `self`.

    OUTPUT: `toric lattice`

    Note

    For any ambient toric lattice its ambient module is the lattice itself.

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: N.ambient_module()
        3-d lattice N
        sage: N.ambient_module() is N
        True

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> N.ambient_module()
        3-d lattice N
        >>> N.ambient_module() is N
        True

  dual()

    Return the lattice dual to `self`.

    OUTPUT: `toric lattice`

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: N
        3-d lattice N
        sage: M = N.dual()
        sage: M
        3-d lattice M
        sage: M.dual() is N
        True

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> N
        3-d lattice N
        >>> M = N.dual()
        >>> M
        3-d lattice M
        >>> M.dual() is N
        True

    Elements of dual lattices can act on each other:

    Sage

        sage: n = N(1,2,3)
        sage: m = M(4,5,6)
        sage: n * m
        32
        sage: m * n
        32

    [Python]

        >>> from sage.all import *
        >>> n = N(Integer(1),Integer(2),Integer(3))
        >>> m = M(Integer(4),Integer(5),Integer(6))
        >>> n * m
        32
        >>> m * n
        32

  plot(**options)

    Plot `self`.

    INPUT:

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

    OUTPUT: a plot

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: N.plot()                                                              # needs sage.plot
        Graphics3d Object

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> N.plot()                                                              # needs sage.plot
        Graphics3d Object

class sage.geometry.toric_lattice.ToricLattice_generic(base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None)

  Bases: `FreeModule_generic_pid`

  Abstract base class for toric lattices.

  Element

    alias of `ToricLatticeElement`

  construction()

    Return the functorial construction of `self`.

    OUTPUT:

    `None`, we do not think of toric lattices as constructed from simpler objects since we do not want to perform arithmetic involving different lattices.

  direct_sum(other)

    Return the direct sum with `other`.

    INPUT:

    - `other` – a toric lattice or more general module

    OUTPUT:

    The direct sum of `self` and `other` as \(\ZZ\)-modules. If `other` is a `ToricLattice`, another toric lattice will be returned.

    EXAMPLES:

    Sage

        sage: K = ToricLattice(3, 'K')
        sage: L = ToricLattice(3, 'L')
        sage: N = K.direct_sum(L); N
        6-d lattice K+L
        sage: N, N.dual(), latex(N), latex(N.dual())
        (6-d lattice K+L, 6-d lattice K*+L*, K \oplus L, K^* \oplus L^*)

    Python

        >>> from sage.all import *
        >>> K = ToricLattice(Integer(3), 'K')
        >>> L = ToricLattice(Integer(3), 'L')
        >>> N = K.direct_sum(L); N
        6-d lattice K+L
        >>> N, N.dual(), latex(N), latex(N.dual())
        (6-d lattice K+L, 6-d lattice K*+L*, K \oplus L, K^* \oplus L^*)

    With default names:

    Sage

        sage: N = ToricLattice(3).direct_sum(ToricLattice(2))
        sage: N, N.dual(), latex(N), latex(N.dual())
        (5-d lattice N+N, 5-d lattice M+M, N \oplus N, M \oplus M)

    [Python]

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3)).direct_sum(ToricLattice(Integer(2)))
        >>> N, N.dual(), latex(N), latex(N.dual())
        (5-d lattice N+N, 5-d lattice M+M, N \oplus N, M \oplus M)

    If `other` is not a `ToricLattice`, fall back to sum of modules:

    Sage

        sage: ToricLattice(3).direct_sum(ZZ^2)
        Free module of degree 5 and rank 5 over Integer Ring
        Echelon basis matrix:
        [1 0 0 0 0]
        [0 1 0 0 0]
        [0 0 1 0 0]
        [0 0 0 1 0]
        [0 0 0 0 1]

    Python

        >>> from sage.all import *
        >>> ToricLattice(Integer(3)).direct_sum(ZZ**Integer(2))
        Free module of degree 5 and rank 5 over Integer Ring
        Echelon basis matrix:
        [1 0 0 0 0]
        [0 1 0 0 0]
        [0 0 1 0 0]
        [0 0 0 1 0]
        [0 0 0 0 1]

  intersection(other)

    Return the intersection of `self` and `other`.

    INPUT:

    - `other` – a toric (sub)lattice.dual

    OUTPUT:

    - a toric (sub)lattice.

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns1 = N.submodule([N(2,4,0), N(9,12,0)])
        sage: Ns2 = N.submodule([N(1,4,9), N(9,2,0)])
        sage: Ns1.intersection(Ns2)
        Sublattice <N(54, 12, 0)>

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns1 = N.submodule([N(Integer(2),Integer(4),Integer(0)), N(Integer(9),Integer(12),Integer(0))])
        >>> Ns2 = N.submodule([N(Integer(1),Integer(4),Integer(9)), N(Integer(9),Integer(2),Integer(0))])
        >>> Ns1.intersection(Ns2)
        Sublattice <N(54, 12, 0)>

    Note that if one of the intersecting sublattices is a sublattice of another, no new lattices will be constructed:

    Sage

        sage: N.intersection(N) is N
        True
        sage: Ns1.intersection(N) is Ns1
        True
        sage: N.intersection(Ns1) is Ns1
        True

    [Python]

        >>> from sage.all import *
        >>> N.intersection(N) is N
        True
        >>> Ns1.intersection(N) is Ns1
        True
        >>> N.intersection(Ns1) is Ns1
        True

  quotient(sub, check=True, positive_point=None, positive_dual_point=None, **kwds)

    Return the quotient of `self` by the given sublattice `sub`.

    INPUT:

    - `sub` – sublattice of self

    - `check` – boolean (default: `True`); whether or not to check that `sub` is a valid sublattice

    If the quotient is one-dimensional and torsion free, the following two mutually exclusive keyword arguments are also allowed. They decide the sign choice for the (single) generator of the quotient lattice:

    - `positive_point` – a lattice point of `self` not in the sublattice `sub` (that is, not zero in the quotient lattice). The quotient generator will be in the same direction as `positive_point`.

    - `positive_dual_point` – a dual lattice point. The quotient generator will be chosen such that its lift has a positive product with `positive_dual_point`. Note: if `positive_dual_point` is not zero on the sublattice `sub`, then the notion of positivity will depend on the choice of lift!

    Further named arguments are passed to the constructor of a toric lattice quotient.

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([N(2,4,0), N(9,12,0)])
        sage: Q = N/Ns
        sage: Q
        Quotient with torsion of 3-d lattice N
        by Sublattice <N(1, 8, 0), N(0, 12, 0)>

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([N(Integer(2),Integer(4),Integer(0)), N(Integer(9),Integer(12),Integer(0))])
        >>> Q = N/Ns
        >>> Q
        Quotient with torsion of 3-d lattice N
        by Sublattice <N(1, 8, 0), N(0, 12, 0)>

    Attempting to quotient one lattice by a sublattice of another will result in a `ValueError`:

    Sage

        sage: N = ToricLattice(3)
        sage: M = ToricLattice(3, name='M')
        sage: Ms = M.submodule([M(2,4,0), M(9,12,0)])
        sage: N.quotient(Ms)
        Traceback (most recent call last):
        ...
        ValueError: M(1, 8, 0) cannot generate a sublattice of
        3-d lattice N

    [Python]

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> M = ToricLattice(Integer(3), name='M')
        >>> Ms = M.submodule([M(Integer(2),Integer(4),Integer(0)), M(Integer(9),Integer(12),Integer(0))])
        >>> N.quotient(Ms)
        Traceback (most recent call last):
        ...
        ValueError: M(1, 8, 0) cannot generate a sublattice of
        3-d lattice N

    However, if we forget the sublattice structure, then it is possible to quotient by vector spaces or modules constructed from any sublattice:

    Sage

        sage: N = ToricLattice(3)
        sage: M = ToricLattice(3, name='M')
        sage: Ms = M.submodule([M(2,4,0), M(9,12,0)])
        sage: N.quotient(Ms.vector_space())
        Quotient with torsion of 3-d lattice N by Sublattice
        <N(1, 8, 0), N(0, 12, 0)>
        sage: N.quotient(Ms.sparse_module())
        Quotient with torsion of 3-d lattice N by Sublattice
        <N(1, 8, 0), N(0, 12, 0)>

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> M = ToricLattice(Integer(3), name='M')
        >>> Ms = M.submodule([M(Integer(2),Integer(4),Integer(0)), M(Integer(9),Integer(12),Integer(0))])
        >>> N.quotient(Ms.vector_space())
        Quotient with torsion of 3-d lattice N by Sublattice
        <N(1, 8, 0), N(0, 12, 0)>
        >>> N.quotient(Ms.sparse_module())
        Quotient with torsion of 3-d lattice N by Sublattice
        <N(1, 8, 0), N(0, 12, 0)>

    See `ToricLattice_quotient` for more examples.

  saturation()

    Return the saturation of `self`.

    OUTPUT: a `toric lattice`

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([(1,2,3), (4,5,6)])
        sage: Ns
        Sublattice <N(1, 2, 3), N(0, 3, 6)>
        sage: Ns_sat = Ns.saturation()
        sage: Ns_sat
        Sublattice <N(1, 0, -1), N(0, 1, 2)>
        sage: Ns_sat is Ns_sat.saturation()
        True

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([(Integer(1),Integer(2),Integer(3)), (Integer(4),Integer(5),Integer(6))])
        >>> Ns
        Sublattice <N(1, 2, 3), N(0, 3, 6)>
        >>> Ns_sat = Ns.saturation()
        >>> Ns_sat
        Sublattice <N(1, 0, -1), N(0, 1, 2)>
        >>> Ns_sat is Ns_sat.saturation()
        True

  span(gens, base_ring=Integer Ring, *args, **kwds)

    Return the span of the given generators.

    INPUT:

    - `gens` – list of elements of the ambient vector space of `self`

    - `base_ring` – (default: \(\ZZ\)) base ring for the generated module

    OUTPUT: submodule spanned by `gens`

    Note

    The output need not be a submodule of `self`, nor even of the ambient space. It must, however, be contained in the ambient vector space.

    See also `span_of_basis()`, `submodule()`, and `submodule_with_basis()`,

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([N.gen(0)])
        sage: Ns.span([N.gen(1)])
        Sublattice <N(0, 1, 0)>
        sage: Ns.submodule([N.gen(1)])
        Traceback (most recent call last):
        ...
        ArithmeticError: argument gens (= [N(0, 1, 0)]) does not generate a submodule of self

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([N.gen(Integer(0))])
        >>> Ns.span([N.gen(Integer(1))])
        Sublattice <N(0, 1, 0)>
        >>> Ns.submodule([N.gen(Integer(1))])
        Traceback (most recent call last):
        ...
        ArithmeticError: argument gens (= [N(0, 1, 0)]) does not generate a submodule of self

  span_of_basis(basis, base_ring=Integer Ring, *args, **kwds)

    Return the submodule with the given `basis`.

    INPUT:

    - `basis` – list of elements of the ambient vector space of `self`

    - `base_ring` – (default: \(\ZZ\)) base ring for the generated module

    OUTPUT: submodule spanned by `basis`

    Note

    The output need not be a submodule of `self`, nor even of the ambient space. It must, however, be contained in the ambient vector space.

    See also `span()`, `submodule()`, and `submodule_with_basis()`,

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.span_of_basis([(1,2,3)])
        sage: Ns.span_of_basis([(2,4,0)])
        Sublattice <N(2, 4, 0)>
        sage: Ns.span_of_basis([(1/5,2/5,0), (1/7,1/7,0)])
        Free module of degree 3 and rank 2 over Integer Ring
        User basis matrix:
        [1/5 2/5   0]
        [1/7 1/7   0]

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.span_of_basis([(Integer(1),Integer(2),Integer(3))])
        >>> Ns.span_of_basis([(Integer(2),Integer(4),Integer(0))])
        Sublattice <N(2, 4, 0)>
        >>> Ns.span_of_basis([(Integer(1)/Integer(5),Integer(2)/Integer(5),Integer(0)), (Integer(1)/Integer(7),Integer(1)/Integer(7),Integer(0))])
        Free module of degree 3 and rank 2 over Integer Ring
        User basis matrix:
        [1/5 2/5   0]
        [1/7 1/7   0]

    Of course the input basis vectors must be linearly independent:

    Sage

        sage: Ns.span_of_basis([(1,2,0), (2,4,0)])
        Traceback (most recent call last):
        ...
        ValueError: The given basis vectors must be linearly independent.

    [Python]

        >>> from sage.all import *
        >>> Ns.span_of_basis([(Integer(1),Integer(2),Integer(0)), (Integer(2),Integer(4),Integer(0))])
        Traceback (most recent call last):
        ...
        ValueError: The given basis vectors must be linearly independent.

class sage.geometry.toric_lattice.ToricLattice_quotient(V, W, check=True, positive_point=None, positive_dual_point=None, **kwds)

  Bases: `FGP_Module_class`

  Construct the quotient of a toric lattice `V` by its sublattice `W`.

  INPUT:

  - `V` – ambient toric lattice

  - `W` – sublattice of `V`

  - `check` – boolean (default: `True`); whether to check correctness of input or not

  If the quotient is one-dimensional and torsion free, the following two mutually exclusive keyword arguments are also allowed. They decide the sign choice for the (single) generator of the quotient lattice:

  - `positive_point` – a lattice point of `self` not in the sublattice `sub` (that is, not zero in the quotient lattice). The quotient generator will be in the same direction as `positive_point`.

  - `positive_dual_point` – a dual lattice point. The quotient generator will be chosen such that its lift has a positive product with `positive_dual_point`. Note: if `positive_dual_point` is not zero on the sublattice `sub`, then the notion of positivity will depend on the choice of lift!

  Further given named arguments are passed to the constructor of an FGP module.

  OUTPUT: quotient of `V` by `W`

  EXAMPLES:

  The intended way to get objects of this class is to use `quotient()` method of toric lattices:

  Sage

      sage: N = ToricLattice(3)
      sage: sublattice = N.submodule([(1,1,0), (3,2,1)])
      sage: Q = N/sublattice
      sage: Q
      1-d lattice, quotient of 3-d lattice N by Sublattice <N(1, 0, 1), N(0, 1, -1)>
      sage: Q.gens()
      (N[1, 0, 0],)

  Python

      >>> from sage.all import *
      >>> N = ToricLattice(Integer(3))
      >>> sublattice = N.submodule([(Integer(1),Integer(1),Integer(0)), (Integer(3),Integer(2),Integer(1))])
      >>> Q = N/sublattice
      >>> Q
      1-d lattice, quotient of 3-d lattice N by Sublattice <N(1, 0, 1), N(0, 1, -1)>
      >>> Q.gens()
      (N[1, 0, 0],)

  Here, `sublattice` happens to be of codimension one in `N`. If you want to prescribe the sign of the quotient generator, you can do either:

  Sage

      sage: Q = N.quotient(sublattice, positive_point=N(0,0,-1)); Q
      1-d lattice, quotient of 3-d lattice N by Sublattice <N(1, 0, 1), N(0, 1, -1)>
      sage: Q.gens()
      (N[1, 0, 0],)

  [Python]

      >>> from sage.all import *
      >>> Q = N.quotient(sublattice, positive_point=N(Integer(0),Integer(0),-Integer(1))); Q
      1-d lattice, quotient of 3-d lattice N by Sublattice <N(1, 0, 1), N(0, 1, -1)>
      >>> Q.gens()
      (N[1, 0, 0],)

  or:

  Sage

      sage: M = N.dual()
      sage: Q = N.quotient(sublattice, positive_dual_point=M(1,0,0)); Q
      1-d lattice, quotient of 3-d lattice N by Sublattice <N(1, 0, 1), N(0, 1, -1)>
      sage: Q.gens()
      (N[1, 0, 0],)

  Python

      >>> from sage.all import *
      >>> M = N.dual()
      >>> Q = N.quotient(sublattice, positive_dual_point=M(Integer(1),Integer(0),Integer(0))); Q
      1-d lattice, quotient of 3-d lattice N by Sublattice <N(1, 0, 1), N(0, 1, -1)>
      >>> Q.gens()
      (N[1, 0, 0],)

  Element

    alias of `ToricLattice_quotient_element`

  base_extend(R)

    Return the base change of `self` to the ring `R`.

    INPUT:

    - `R` – either \(\ZZ\) or \(\QQ\)

    OUTPUT: `self` if \(R=\ZZ\), quotient of the base extension of the ambient lattice by the base extension of the sublattice if \(R=\QQ\)

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([N(2,4,0), N(9,12,0)])
        sage: Q = N/Ns
        sage: Q.base_extend(ZZ) is Q
        True
        sage: Q.base_extend(QQ)
        Vector space quotient V/W of dimension 1 over Rational Field where
        V: Vector space of dimension 3 over Rational Field
        W: Vector space of degree 3 and dimension 2 over Rational Field
        Basis matrix:
        [1 0 0]
        [0 1 0]

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([N(Integer(2),Integer(4),Integer(0)), N(Integer(9),Integer(12),Integer(0))])
        >>> Q = N/Ns
        >>> Q.base_extend(ZZ) is Q
        True
        >>> Q.base_extend(QQ)
        Vector space quotient V/W of dimension 1 over Rational Field where
        V: Vector space of dimension 3 over Rational Field
        W: Vector space of degree 3 and dimension 2 over Rational Field
        Basis matrix:
        [1 0 0]
        [0 1 0]

  coordinate_vector(x, reduce=False)

    Return coordinates of `x` with respect to the optimized representation of `self`.

    INPUT:

    - `x` – element of `self` or convertible to `self`

    - `reduce` – (default: `False`) if `True`, reduce coefficients modulo invariants

    OUTPUT: the coordinates as a vector

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Q = N.quotient(N.span([N(1,2,3), N(0,2,1)]), positive_point=N(0,-1,0))
        sage: q = Q.gen(0); q
        N[0, -1, 0]
        sage: q.vector()  # indirect test
        (1)
        sage: Q.coordinate_vector(q)
        (1)

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Q = N.quotient(N.span([N(Integer(1),Integer(2),Integer(3)), N(Integer(0),Integer(2),Integer(1))]), positive_point=N(Integer(0),-Integer(1),Integer(0)))
        >>> q = Q.gen(Integer(0)); q
        N[0, -1, 0]
        >>> q.vector()  # indirect test
        (1)
        >>> Q.coordinate_vector(q)
        (1)

  dimension()

    alias of `rank()`.

  dual()

    Return the lattice dual to `self`.

    OUTPUT: a `toric lattice quotient`

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([(1, -1, -1)])
        sage: Q = N / Ns
        sage: Q.dual()
        Sublattice <M(1, 0, 1), M(0, 1, -1)>

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([(Integer(1), -Integer(1), -Integer(1))])
        >>> Q = N / Ns
        >>> Q.dual()
        Sublattice <M(1, 0, 1), M(0, 1, -1)>

  gens()

    Return the generators of the quotient.

    OUTPUT:

    A tuple of `ToricLattice_quotient_element` generating the quotient.

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Q = N.quotient(N.span([N(1,2,3), N(0,2,1)]), positive_point=N(0,-1,0))
        sage: Q.gens()
        (N[0, -1, 0],)

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Q = N.quotient(N.span([N(Integer(1),Integer(2),Integer(3)), N(Integer(0),Integer(2),Integer(1))]), positive_point=N(Integer(0),-Integer(1),Integer(0)))
        >>> Q.gens()
        (N[0, -1, 0],)

  is_torsion_free()

    Check if `self` is torsion-free.

    OUTPUT: `True` if `self` has no torsion and `False` otherwise

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([N(2,4,0), N(9,12,0)])
        sage: Q = N/Ns
        sage: Q.is_torsion_free()
        False
        sage: Ns = N.submodule([N(1,4,0)])
        sage: Q = N/Ns
        sage: Q.is_torsion_free()
        True

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([N(Integer(2),Integer(4),Integer(0)), N(Integer(9),Integer(12),Integer(0))])
        >>> Q = N/Ns
        >>> Q.is_torsion_free()
        False
        >>> Ns = N.submodule([N(Integer(1),Integer(4),Integer(0))])
        >>> Q = N/Ns
        >>> Q.is_torsion_free()
        True

  rank()

    Return the rank of `self`.

    OUTPUT: integer; the dimension of the free part of the quotient

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([N(2,4,0), N(9,12,0)])
        sage: Q = N/Ns
        sage: Q.ngens()
        2
        sage: Q.rank()
        1
        sage: Ns = N.submodule([N(1,4,0)])
        sage: Q = N/Ns
        sage: Q.ngens()
        2
        sage: Q.rank()
        2

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([N(Integer(2),Integer(4),Integer(0)), N(Integer(9),Integer(12),Integer(0))])
        >>> Q = N/Ns
        >>> Q.ngens()
        2
        >>> Q.rank()
        1
        >>> Ns = N.submodule([N(Integer(1),Integer(4),Integer(0))])
        >>> Q = N/Ns
        >>> Q.ngens()
        2
        >>> Q.rank()
        2

class sage.geometry.toric_lattice.ToricLattice_quotient_element(parent, x, check=True)

  Bases: `FGP_Element`

  Create an element of a toric lattice quotient.

  Warning

  You probably should not construct such elements explicitly.

  INPUT:

  - same as for `FGP_Element`.

  OUTPUT: element of a toric lattice quotient

  set_immutable()

    Make `self` immutable.

    OUTPUT: none

    Note

    Elements of toric lattice quotients are always immutable, so this method does nothing, it is introduced for compatibility purposes only.

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([N(2,4,0), N(9,12,0)])
        sage: Q = N/Ns
        sage: Q.0.set_immutable()

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([N(Integer(2),Integer(4),Integer(0)), N(Integer(9),Integer(12),Integer(0))])
        >>> Q = N/Ns
        >>> Q.gen(0).set_immutable()

class sage.geometry.toric_lattice.ToricLattice_sublattice(ambient, gens, check=True, already_echelonized=False, category=None)

  Bases: `ToricLattice_sublattice_with_basis`, `FreeModule_submodule_pid`

  Construct the sublattice of `ambient` toric lattice generated by `gens`.

  INPUT (same as for `FreeModule_submodule_pid`):

  - `ambient` – ambient `toric lattice` for this sublattice

  - `gens` – list of elements of `ambient` generating the constructed sublattice

  - see the base class for other available options

  OUTPUT: sublattice of a toric lattice with an automatically chosen basis

  See also `ToricLattice_sublattice_with_basis` if you want to specify an explicit basis.

  EXAMPLES:

  The intended way to get objects of this class is to use `submodule()` method of toric lattices:

  Sage

      sage: N = ToricLattice(3)
      sage: sublattice = N.submodule([(1,1,0), (3,2,1)])
      sage: sublattice.has_user_basis()
      False
      sage: sublattice.basis()
      [N(1, 0, 1), N(0, 1, -1)]

  Python

      >>> from sage.all import *
      >>> N = ToricLattice(Integer(3))
      >>> sublattice = N.submodule([(Integer(1),Integer(1),Integer(0)), (Integer(3),Integer(2),Integer(1))])
      >>> sublattice.has_user_basis()
      False
      >>> sublattice.basis()
      [N(1, 0, 1), N(0, 1, -1)]

  For sublattices without user-specified basis, the basis obtained above is the same as the “standard” one:

  Sage

      sage: sublattice.echelonized_basis()
      [N(1, 0, 1), N(0, 1, -1)]

  [Python]

      >>> from sage.all import *
      >>> sublattice.echelonized_basis()
      [N(1, 0, 1), N(0, 1, -1)]

class sage.geometry.toric_lattice.ToricLattice_sublattice_with_basis(ambient, basis, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False, category=None)

  Bases: `ToricLattice_generic`, `FreeModule_submodule_with_basis_pid`

  Construct the sublattice of `ambient` toric lattice with given `basis`.

  INPUT (same as for `FreeModule_submodule_with_basis_pid`):

  - `ambient` – ambient `toric lattice` for this sublattice

  - `basis` – list of linearly independent elements of `ambient`, these elements will be used as the default basis of the constructed sublattice

  - see the base class for other available options

  OUTPUT: sublattice of a toric lattice with a user-specified basis

  See also `ToricLattice_sublattice` if you do not want to specify an explicit basis.

  EXAMPLES:

  The intended way to get objects of this class is to use `submodule_with_basis()` method of toric lattices:

  Sage

      sage: N = ToricLattice(3)
      sage: sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)])
      sage: sublattice.has_user_basis()
      True
      sage: sublattice.basis()
      [N(1, 1, 0), N(3, 2, 1)]

  Python

      >>> from sage.all import *
      >>> N = ToricLattice(Integer(3))
      >>> sublattice = N.submodule_with_basis([(Integer(1),Integer(1),Integer(0)), (Integer(3),Integer(2),Integer(1))])
      >>> sublattice.has_user_basis()
      True
      >>> sublattice.basis()
      [N(1, 1, 0), N(3, 2, 1)]

  Even if you have provided your own basis, you still can access the “standard” one:

  Sage

      sage: sublattice.echelonized_basis()
      [N(1, 0, 1), N(0, 1, -1)]

  [Python]

      >>> from sage.all import *
      >>> sublattice.echelonized_basis()
      [N(1, 0, 1), N(0, 1, -1)]

  dual()

    Return the lattice dual to `self`.

    OUTPUT: a `toric lattice quotient`

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: Ns = N.submodule([(1,1,0), (3,2,1)])
        sage: Ns.dual()
        2-d lattice, quotient of 3-d lattice M by Sublattice <M(1, -1, -1)>

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> Ns = N.submodule([(Integer(1),Integer(1),Integer(0)), (Integer(3),Integer(2),Integer(1))])
        >>> Ns.dual()
        2-d lattice, quotient of 3-d lattice M by Sublattice <M(1, -1, -1)>

  plot(**options)

    Plot `self`.

    INPUT:

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

    OUTPUT: a plot

    EXAMPLES:

    Sage

        sage: N = ToricLattice(3)
        sage: sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)])
        sage: sublattice.plot()                                                     # needs sage.plot
        Graphics3d Object

    Python

        >>> from sage.all import *
        >>> N = ToricLattice(Integer(3))
        >>> sublattice = N.submodule_with_basis([(Integer(1),Integer(1),Integer(0)), (Integer(3),Integer(2),Integer(1))])
        >>> sublattice.plot()                                                     # needs sage.plot
        Graphics3d Object

    Now we plot both the ambient lattice and its sublattice:

    Sage

        sage: N.plot() + sublattice.plot(point_color='red')                         # needs sage.plot
        Graphics3d Object

    [Python]

        >>> from sage.all import *
        >>> N.plot() + sublattice.plot(point_color='red')                         # needs sage.plot
        Graphics3d Object

sage.geometry.toric_lattice.is_ToricLattice(x)

  Check if `x` is a toric lattice.

  INPUT:

  - `x` – anything

  OUTPUT: `True` if `x` is a toric lattice and `False` otherwise

  EXAMPLES:

  Sage

      sage: from sage.geometry.toric_lattice import (
      ....:   is_ToricLattice)
      sage: is_ToricLattice(1)
      doctest:warning...
      DeprecationWarning: The function is_ToricLattice is deprecated;
      use 'isinstance(..., ToricLattice_generic)' instead.
      See https://github.com/sagemath/sage/issues/38126 for details.
      False
      sage: N = ToricLattice(3)
      sage: N
      3-d lattice N
      sage: is_ToricLattice(N)
      True

  Python

      >>> from sage.all import *
      >>> from sage.geometry.toric_lattice import (
      ...   is_ToricLattice)
      >>> is_ToricLattice(Integer(1))
      doctest:warning...
      DeprecationWarning: The function is_ToricLattice is deprecated;
      use 'isinstance(..., ToricLattice_generic)' instead.
      See https://github.com/sagemath/sage/issues/38126 for details.
      False
      >>> N = ToricLattice(Integer(3))
      >>> N
      3-d lattice N
      >>> is_ToricLattice(N)
      True

sage.geometry.toric_lattice.is_ToricLatticeQuotient(x)

  Check if `x` is a toric lattice quotient.

  INPUT:

  - `x` – anything

  OUTPUT: `True` if `x` is a toric lattice quotient and `False` otherwise

  EXAMPLES:

  Sage

      sage: from sage.geometry.toric_lattice import (
      ....:   is_ToricLatticeQuotient)
      sage: is_ToricLatticeQuotient(1)
      doctest:warning...
      DeprecationWarning: The function is_ToricLatticeQuotient is deprecated;
      use 'isinstance(..., ToricLattice_quotient)' instead.
      See https://github.com/sagemath/sage/issues/38126 for details.
      False
      sage: N = ToricLattice(3)
      sage: N
      3-d lattice N
      sage: is_ToricLatticeQuotient(N)
      False
      sage: Q = N / N.submodule([(1,2,3), (3,2,1)])
      sage: Q
      Quotient with torsion of 3-d lattice N
      by Sublattice <N(1, 2, 3), N(0, 4, 8)>
      sage: is_ToricLatticeQuotient(Q)
      True

  Python

      >>> from sage.all import *
      >>> from sage.geometry.toric_lattice import (
      ...   is_ToricLatticeQuotient)
      >>> is_ToricLatticeQuotient(Integer(1))
      doctest:warning...
      DeprecationWarning: The function is_ToricLatticeQuotient is deprecated;
      use 'isinstance(..., ToricLattice_quotient)' instead.
      See https://github.com/sagemath/sage/issues/38126 for details.
      False
      >>> N = ToricLattice(Integer(3))
      >>> N
      3-d lattice N
      >>> is_ToricLatticeQuotient(N)
      False
      >>> Q = N / N.submodule([(Integer(1),Integer(2),Integer(3)), (Integer(3),Integer(2),Integer(1))])
      >>> Q
      Quotient with torsion of 3-d lattice N
      by Sublattice <N(1, 2, 3), N(0, 4, 8)>
      >>> is_ToricLatticeQuotient(Q)
      True