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: N = ToricLattice(3)
sage: N
3-d lattice N
>>> from sage.all import *
>>> N = ToricLattice(Integer(3))
>>> N
3-d lattice N
N = ToricLattice(3)
N

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

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

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

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

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

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

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: another_N = ToricLattice(3, "N")
sage: another_N.dual()
3-d lattice N*
sage: N is another_N
False
>>> from sage.all import *
>>> another_N = ToricLattice(Integer(3), "N")
>>> another_N.dual()
3-d lattice N*
>>> N is another_N
False
another_N = ToricLattice(3, "N")
another_N.dual()
N is another_N

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

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)
>>> 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)
n = N([1,2,3])
n
M = N.dual()
m = M(1,2,3)
m

Dual lattices can act on each other:

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

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

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

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

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
>>> 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
n + m
n * n
n == m

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

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: 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
>>> 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
ZZ3 = ZZ^3
n_in_M = M(ZZ3(n))
n_in_M
n == n_in_M
n_in_M == m

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

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

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: (1,2,3) + (1,2,3)
(1, 2, 3, 1, 2, 3)
>>> from sage.all import *
>>> (Integer(1),Integer(2),Integer(3)) + (Integer(1),Integer(2),Integer(3))
(1, 2, 3, 1, 2, 3)
(1,2,3) + (1,2,3)

Instead, use syntax like

sage: N(1,2,3) + N(1,2,3)
N(2, 4, 6)
>>> from sage.all import *
>>> N(Integer(1),Integer(2),Integer(3)) + N(Integer(1),Integer(2),Integer(3))
N(2, 4, 6)
N(1,2,3) + N(1,2,3)
class sage.geometry.toric_lattice.ToricLatticeFactory[source]

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: L1 = ToricLattice(3)
sage: L1
3-d lattice N
sage: L1.dual()
3-d lattice M
>>> from sage.all import *
>>> L1 = ToricLattice(Integer(3))
>>> L1
3-d lattice N
>>> L1.dual()
3-d lattice M
L1 = ToricLattice(3)
L1
L1.dual()

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

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

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

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

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

sage: L4 = ToricLattice(3, "N", "M", r"\mathbb{N}", r"\mathbb{M}")
sage: latex(L4)
\mathbb{N}
sage: latex(L4.dual())
\mathbb{M}
>>> 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}
L4 = ToricLattice(3, "N", "M", r"\mathbb{N}", r"\mathbb{M}")
latex(L4)
latex(L4.dual())

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

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

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)[source]

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)[source]

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)[source]

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[source]

alias of ToricLatticeElement

ambient_module()[source]

Return the ambient module of self.

OUTPUT: toric lattice

Note

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

EXAMPLES:

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

Return the lattice dual to self.

OUTPUT: toric lattice

EXAMPLES:

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
>>> 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
N = ToricLattice(3)
N
M = N.dual()
M
M.dual() is N

Elements of dual lattices can act on each other:

sage: n = N(1,2,3)
sage: m = M(4,5,6)
sage: n * m
32
sage: m * n
32
>>> 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
n = N(1,2,3)
m = M(4,5,6)
n * m
m * n
plot(**options)[source]

Plot self.

INPUT:

OUTPUT: a plot

EXAMPLES:

sage: N = ToricLattice(3)
sage: N.plot()                                                              # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> N = ToricLattice(Integer(3))
>>> N.plot()                                                              # needs sage.plot
Graphics3d Object
N = ToricLattice(3)
N.plot()                                                              # needs sage.plot
class sage.geometry.toric_lattice.ToricLattice_generic(base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None)[source]

Bases: FreeModule_generic_pid

Abstract base class for toric lattices.

Element[source]

alias of ToricLatticeElement

construction()[source]

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)[source]

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: 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^*)
>>> 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^*)
K = ToricLattice(3, 'K')
L = ToricLattice(3, 'L')
N = K.direct_sum(L); N
N, N.dual(), latex(N), latex(N.dual())

With default names:

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)
>>> 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)
N = ToricLattice(3).direct_sum(ToricLattice(2))
N, N.dual(), latex(N), latex(N.dual())

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

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]
>>> 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]
ToricLattice(3).direct_sum(ZZ^2)
intersection(other)[source]

Return the intersection of self and other.

INPUT:

  • other – a toric (sub)lattice.dual

OUTPUT:

  • a toric (sub)lattice.

EXAMPLES:

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)>
>>> 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)>
N = ToricLattice(3)
Ns1 = N.submodule([N(2,4,0), N(9,12,0)])
Ns2 = N.submodule([N(1,4,9), N(9,2,0)])
Ns1.intersection(Ns2)

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

sage: N.intersection(N) is N
True
sage: Ns1.intersection(N) is Ns1
True
sage: N.intersection(Ns1) is Ns1
True
>>> from sage.all import *
>>> N.intersection(N) is N
True
>>> Ns1.intersection(N) is Ns1
True
>>> N.intersection(Ns1) is Ns1
True
N.intersection(N) is N
Ns1.intersection(N) is Ns1
N.intersection(Ns1) is Ns1
quotient(sub, check=True, positive_point=None, positive_dual_point=None, **kwds)[source]

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: 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)>
>>> 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)>
N = ToricLattice(3)
Ns = N.submodule([N(2,4,0), N(9,12,0)])
Q = N/Ns
Q

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

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
>>> 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
N = ToricLattice(3)
M = ToricLattice(3, name='M')
Ms = M.submodule([M(2,4,0), M(9,12,0)])
N.quotient(Ms)

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

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)>
>>> 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)>
N = ToricLattice(3)
M = ToricLattice(3, name='M')
Ms = M.submodule([M(2,4,0), M(9,12,0)])
N.quotient(Ms.vector_space())
N.quotient(Ms.sparse_module())

See ToricLattice_quotient for more examples.

saturation()[source]

Return the saturation of self.

OUTPUT: a toric lattice

EXAMPLES:

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
>>> 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
N = ToricLattice(3)
Ns = N.submodule([(1,2,3), (4,5,6)])
Ns
Ns_sat = Ns.saturation()
Ns_sat
Ns_sat is Ns_sat.saturation()
span(gens, base_ring=Integer Ring, *args, **kwds)[source]

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: 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
>>> 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
N = ToricLattice(3)
Ns = N.submodule([N.gen(0)])
Ns.span([N.gen(1)])
Ns.submodule([N.gen(1)])
span_of_basis(basis, base_ring=Integer Ring, *args, **kwds)[source]

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: 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]
>>> 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]
N = ToricLattice(3)
Ns = N.span_of_basis([(1,2,3)])
Ns.span_of_basis([(2,4,0)])
Ns.span_of_basis([(1/5,2/5,0), (1/7,1/7,0)])

Of course the input basis vectors must be linearly independent:

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.
>>> 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.
Ns.span_of_basis([(1,2,0), (2,4,0)])
class sage.geometry.toric_lattice.ToricLattice_quotient(V, W, check=True, positive_point=None, positive_dual_point=None, **kwds)[source]

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: 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],)
>>> 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],)
N = ToricLattice(3)
sublattice = N.submodule([(1,1,0), (3,2,1)])
Q = N/sublattice
Q
Q.gens()

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: 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],)
>>> 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],)
Q = N.quotient(sublattice, positive_point=N(0,0,-1)); Q
Q.gens()

or:

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],)
>>> 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],)
M = N.dual()
Q = N.quotient(sublattice, positive_dual_point=M(1,0,0)); Q
Q.gens()
Element[source]

alias of ToricLattice_quotient_element

base_extend(R)[source]

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: 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]
>>> 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]
N = ToricLattice(3)
Ns = N.submodule([N(2,4,0), N(9,12,0)])
Q = N/Ns
Q.base_extend(ZZ) is Q
Q.base_extend(QQ)
coordinate_vector(x, reduce=False)[source]

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: 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)
>>> 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)
N = ToricLattice(3)
Q = N.quotient(N.span([N(1,2,3), N(0,2,1)]), positive_point=N(0,-1,0))
q = Q.gen(0); q
q.vector()  # indirect test
Q.coordinate_vector(q)
dimension()[source]

Return the rank of self.

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

EXAMPLES:

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
>>> 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
N = ToricLattice(3)
Ns = N.submodule([N(2,4,0), N(9,12,0)])
Q = N/Ns
Q.ngens()
Q.rank()
Ns = N.submodule([N(1,4,0)])
Q = N/Ns
Q.ngens()
Q.rank()
dual()[source]

Return the lattice dual to self.

OUTPUT: a toric lattice quotient

EXAMPLES:

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)>
>>> 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)>
N = ToricLattice(3)
Ns = N.submodule([(1, -1, -1)])
Q = N / Ns
Q.dual()
gens()[source]

Return the generators of the quotient.

OUTPUT:

A tuple of ToricLattice_quotient_element generating the quotient.

EXAMPLES:

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],)
>>> 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],)
N = ToricLattice(3)
Q = N.quotient(N.span([N(1,2,3), N(0,2,1)]), positive_point=N(0,-1,0))
Q.gens()
is_torsion_free()[source]

Check if self is torsion-free.

OUTPUT: True if self has no torsion and False otherwise

EXAMPLES:

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
>>> 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
N = ToricLattice(3)
Ns = N.submodule([N(2,4,0), N(9,12,0)])
Q = N/Ns
Q.is_torsion_free()
Ns = N.submodule([N(1,4,0)])
Q = N/Ns
Q.is_torsion_free()
rank()[source]

Return the rank of self.

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

EXAMPLES:

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
>>> 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
N = ToricLattice(3)
Ns = N.submodule([N(2,4,0), N(9,12,0)])
Q = N/Ns
Q.ngens()
Q.rank()
Ns = N.submodule([N(1,4,0)])
Q = N/Ns
Q.ngens()
Q.rank()
class sage.geometry.toric_lattice.ToricLattice_quotient_element(parent, x, check=True)[source]

Bases: FGP_Element

Create an element of a toric lattice quotient.

Warning

You probably should not construct such elements explicitly.

INPUT:

OUTPUT: element of a toric lattice quotient

set_immutable()[source]

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: N = ToricLattice(3)
sage: Ns = N.submodule([N(2,4,0), N(9,12,0)])
sage: Q = N/Ns
sage: Q.0.set_immutable()
>>> 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()
N = ToricLattice(3)
Ns = N.submodule([N(2,4,0), N(9,12,0)])
Q = N/Ns
Q.0.set_immutable()
class sage.geometry.toric_lattice.ToricLattice_sublattice(ambient, gens, check=True, already_echelonized=False, category=None)[source]

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: 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)
]
>>> 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)
]
N = ToricLattice(3)
sublattice = N.submodule([(1,1,0), (3,2,1)])
sublattice.has_user_basis()
sublattice.basis()

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

sage: sublattice.echelonized_basis()
[
N(1, 0, 1),
N(0, 1, -1)
]
>>> from sage.all import *
>>> sublattice.echelonized_basis()
[
N(1, 0, 1),
N(0, 1, -1)
]
sublattice.echelonized_basis()
class sage.geometry.toric_lattice.ToricLattice_sublattice_with_basis(ambient, basis, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False, category=None)[source]

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: 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)
]
>>> 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)
]
N = ToricLattice(3)
sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)])
sublattice.has_user_basis()
sublattice.basis()

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

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

Return the lattice dual to self.

OUTPUT: a toric lattice quotient

EXAMPLES:

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)>
>>> 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)>
N = ToricLattice(3)
Ns = N.submodule([(1,1,0), (3,2,1)])
Ns.dual()
plot(**options)[source]

Plot self.

INPUT:

OUTPUT: a plot

EXAMPLES:

sage: N = ToricLattice(3)
sage: sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)])
sage: sublattice.plot()                                                     # needs sage.plot
Graphics3d Object
>>> 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
N = ToricLattice(3)
sublattice = N.submodule_with_basis([(1,1,0), (3,2,1)])
sublattice.plot()                                                     # needs sage.plot

Now we plot both the ambient lattice and its sublattice:

sage: N.plot() + sublattice.plot(point_color='red')                         # needs sage.plot
Graphics3d Object
>>> from sage.all import *
>>> N.plot() + sublattice.plot(point_color='red')                         # needs sage.plot
Graphics3d Object
N.plot() + sublattice.plot(point_color='red')                         # needs sage.plot
sage.geometry.toric_lattice.is_ToricLattice(x)[source]

Check if x is a toric lattice.

INPUT:

  • x – anything

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

EXAMPLES:

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
>>> 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
from sage.geometry.toric_lattice import (
  is_ToricLattice)
is_ToricLattice(1)
N = ToricLattice(3)
N
is_ToricLattice(N)
sage.geometry.toric_lattice.is_ToricLatticeQuotient(x)[source]

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: 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
>>> 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
from sage.geometry.toric_lattice import (
  is_ToricLatticeQuotient)
is_ToricLatticeQuotient(1)
N = ToricLattice(3)
N
is_ToricLatticeQuotient(N)
Q = N / N.submodule([(1,2,3), (3,2,1)])
Q
is_ToricLatticeQuotient(Q)