Finite \(\ZZ\)-modules with bilinear and quadratic forms¶
AUTHORS:
Simon Brandhorst (2017-09): First created
- sage.modules.torsion_quadratic_module.TorsionQuadraticForm(q)[source]¶
Create a torsion quadratic form module from a rational matrix.
The resulting quadratic form takes values in \(\QQ / \ZZ\) or \(\QQ / 2 \ZZ\) (depending on
q
). If it takes values modulo \(2\), then it is non-degenerate. In any case the bilinear form is non-degenerate.INPUT:
q
– a symmetric rational matrix
EXAMPLES:
sage: q1 = Matrix(QQ, 2, [1,1/2,1/2,1]) sage: TorsionQuadraticForm(q1) Finite quadratic module over Integer Ring with invariants (2, 2) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1]
>>> from sage.all import * >>> q1 = Matrix(QQ, Integer(2), [Integer(1),Integer(1)/Integer(2),Integer(1)/Integer(2),Integer(1)]) >>> TorsionQuadraticForm(q1) Finite quadratic module over Integer Ring with invariants (2, 2) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1]
In the following example the quadratic form is degenerate. But the bilinear form is still non-degenerate:
sage: q2 = diagonal_matrix(QQ, [1/4,1/3]) sage: TorsionQuadraticForm(q2) Finite quadratic module over Integer Ring with invariants (12,) Gram matrix of the quadratic form with values in Q/Z: [7/12]
>>> from sage.all import * >>> q2 = diagonal_matrix(QQ, [Integer(1)/Integer(4),Integer(1)/Integer(3)]) >>> TorsionQuadraticForm(q2) Finite quadratic module over Integer Ring with invariants (12,) Gram matrix of the quadratic form with values in Q/Z: [7/12]
- class sage.modules.torsion_quadratic_module.TorsionQuadraticModule(V, W, gens, modulus, modulus_qf)[source]¶
Bases:
FGP_Module_class
,CachedRepresentation
Finite quotients with a bilinear and a quadratic form.
Let \(V\) be a symmetric
FreeQuadraticModule
and \(W \subseteq V\) a submodule of the same rank as \(V\). The quotient \(V / W\) is a torsion quadratic module. It inherits a bilinear form \(b\) and a quadratic form \(q\).\(b: V \times V \to \QQ / m\ZZ\), where \(m\ZZ = (V,W)\) and \(b(x,y) = (x,y) + m\ZZ\)
\(q: V \to \QQ / n\ZZ\), where \(n\ZZ = 2(V,W) + \ZZ \{ (w,w) | w \in W \}\)
INPUT:
V
– aFreeModule
with a symmetric inner product matrixW
– a submodule ofV
of the same rank asV
check
– boolean (default:True
)modulus
– a rational number dividing \(m\) (default: \(m\)); the inner product \(b\) is defined in \(\QQ /\)modulus
\(\ZZ\)modulus_qf
– a rational number dividing \(n\) (default: \(n\)); the quadratic form \(q\) is defined in \(\QQ /\)modulus_qf
\(\ZZ\)
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeModule(ZZ, 3) sage: T = TorsionQuadraticModule(V, 5*V); T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/5Z: [1 0 0] [0 1 0] [0 0 1]
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = FreeModule(ZZ, Integer(3)) >>> T = TorsionQuadraticModule(V, Integer(5)*V); T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/5Z: [1 0 0] [0 1 0] [0 0 1]
- Element[source]¶
alias of
TorsionQuadraticModuleElement
- all_submodules()[source]¶
Return a list of all submodules of
self
.Warning
This method creates all submodules in memory. The number of submodules grows rapidly with the number of generators. For example consider a vector space of dimension \(n\) over a finite field of prime order \(p\). The number of subspaces is (very) roughly \(p^{(n^2-n)/2}\).
EXAMPLES:
sage: D = IntegralLattice("D4").discriminant_group() # needs sage.combinat sage: D.all_submodules() # needs sage.combinat [Finite quadratic module over Integer Ring with invariants () Gram matrix of the quadratic form with values in Q/2Z: [], Finite quadratic module over Integer Ring with invariants (2,) Gram matrix of the quadratic form with values in Q/2Z: [1], Finite quadratic module over Integer Ring with invariants (2,) Gram matrix of the quadratic form with values in Q/2Z: [1], Finite quadratic module over Integer Ring with invariants (2,) Gram matrix of the quadratic form with values in Q/2Z: [1], Finite quadratic module over Integer Ring with invariants (2, 2) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1]]
>>> from sage.all import * >>> D = IntegralLattice("D4").discriminant_group() # needs sage.combinat >>> D.all_submodules() # needs sage.combinat [Finite quadratic module over Integer Ring with invariants () Gram matrix of the quadratic form with values in Q/2Z: [], Finite quadratic module over Integer Ring with invariants (2,) Gram matrix of the quadratic form with values in Q/2Z: [1], Finite quadratic module over Integer Ring with invariants (2,) Gram matrix of the quadratic form with values in Q/2Z: [1], Finite quadratic module over Integer Ring with invariants (2,) Gram matrix of the quadratic form with values in Q/2Z: [1], Finite quadratic module over Integer Ring with invariants (2, 2) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1]]
- brown_invariant()[source]¶
Return the Brown invariant of this torsion quadratic form.
Let \((D,q)\) be a torsion quadratic module with values in \(\QQ / 2 \ZZ\). The Brown invariant \(Br(D,q) \in \Zmod{8}\) is defined by the equation
\[\exp \left( \frac{2 \pi i }{8} Br(q)\right) = \frac{1}{\sqrt{D}} \sum_{x \in D} \exp(i \pi q(x)).\]The Brown invariant is additive with respect to direct sums of torsion quadratic modules.
OUTPUT: an element of \(\Zmod{8}\)
EXAMPLES:
sage: L = IntegralLattice("D4") # needs sage.combinat sage: D = L.discriminant_group() # needs sage.combinat sage: D.brown_invariant() # needs sage.combinat 4
>>> from sage.all import * >>> L = IntegralLattice("D4") # needs sage.combinat >>> D = L.discriminant_group() # needs sage.combinat >>> D.brown_invariant() # needs sage.combinat 4
We require the quadratic form to be defined modulo \(2 \ZZ\):
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)) sage: T = TorsionQuadraticModule((1/10)*V, V) sage: T.brown_invariant() Traceback (most recent call last): ... ValueError: the torsion quadratic form must have values in QQ / 2 ZZ
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = FreeQuadraticModule(ZZ, Integer(3), matrix.identity(Integer(3))) >>> T = TorsionQuadraticModule((Integer(1)/Integer(10))*V, V) >>> T.brown_invariant() Traceback (most recent call last): ... ValueError: the torsion quadratic form must have values in QQ / 2 ZZ
- gens()[source]¶
Return generators of
self
.There is no assumption on the generators except that they generate the module.
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeModule(ZZ, 3) sage: T = TorsionQuadraticModule(V, 5*V) sage: T.gens() ((1, 0, 0), (0, 1, 0), (0, 0, 1))
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = FreeModule(ZZ, Integer(3)) >>> T = TorsionQuadraticModule(V, Integer(5)*V) >>> T.gens() ((1, 0, 0), (0, 1, 0), (0, 0, 1))
- genus(signature_pair)[source]¶
Return the genus defined by
self
and thesignature_pair
.If no such genus exists, raise a
ValueError
.REFERENCES:
[Nik1977] Corollary 1.9.4 and 1.16.3.
EXAMPLES:
sage: # needs sage.combinat sage: L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) sage: D = L.discriminant_group() sage: genus = D.genus(L.signature_pair()) # needs sage.libs.pari sage: genus # needs sage.libs.pari Genus of None Signature: (6, 0) Genus symbol at 2: 1^4:2^-2 Genus symbol at 3: 1^-5 3^-1 sage: genus == L.genus() # needs sage.libs.pari True
>>> from sage.all import * >>> # needs sage.combinat >>> L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) >>> D = L.discriminant_group() >>> genus = D.genus(L.signature_pair()) # needs sage.libs.pari >>> genus # needs sage.libs.pari Genus of None Signature: (6, 0) Genus symbol at 2: 1^4:2^-2 Genus symbol at 3: 1^-5 3^-1 >>> genus == L.genus() # needs sage.libs.pari True
Let \(H\) be an even unimodular lattice of signature \((9, 1)\). Then \(L = D_4 + A_2\) is primitively embedded in \(H\). We compute the discriminant form of the orthogonal complement of \(L\) in \(H\):
sage: DK = D.twist(-1) # needs sage.combinat sage.libs.pari sage: DK # needs sage.combinat sage.libs.pari Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3]
>>> from sage.all import * >>> DK = D.twist(-Integer(1)) # needs sage.combinat sage.libs.pari >>> DK # needs sage.combinat sage.libs.pari Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3]
We know that \(K\) has signature \((5, 1)\) and thus we can compute the genus of \(K\) as:
sage: DK.genus((3,1)) # needs sage.combinat sage.libs.pari Genus of None Signature: (3, 1) Genus symbol at 2: 1^2:2^-2 Genus symbol at 3: 1^-3 3^1
>>> from sage.all import * >>> DK.genus((Integer(3),Integer(1))) # needs sage.combinat sage.libs.pari Genus of None Signature: (3, 1) Genus symbol at 2: 1^2:2^-2 Genus symbol at 3: 1^-3 3^1
We can also compute the genus of an odd lattice from its discriminant form:
sage: L = IntegralLattice(matrix.diagonal(range(1, 5))) sage: D = L.discriminant_group() sage: D.genus((4,0)) # needs sage.libs.pari Genus of None Signature: (4, 0) Genus symbol at 2: [1^-2 2^1 4^1]_6 Genus symbol at 3: 1^-3 3^1
>>> from sage.all import * >>> L = IntegralLattice(matrix.diagonal(range(Integer(1), Integer(5)))) >>> D = L.discriminant_group() >>> D.genus((Integer(4),Integer(0))) # needs sage.libs.pari Genus of None Signature: (4, 0) Genus symbol at 2: [1^-2 2^1 4^1]_6 Genus symbol at 3: 1^-3 3^1
- gram_matrix_bilinear()[source]¶
Return the Gram matrix with respect to the generators.
OUTPUT:
A rational matrix
G
withG[i,j]
given by the inner product of the \(i\)-th and \(j\)-th generator. Its entries are only well defined \(\mod (V, W)\).EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)*5) sage: T = TorsionQuadraticModule((1/5)*V, V) sage: T.gram_matrix_bilinear() [1/5 0 0] [ 0 1/5 0] [ 0 0 1/5]
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = FreeQuadraticModule(ZZ, Integer(3), matrix.identity(Integer(3))*Integer(5)) >>> T = TorsionQuadraticModule((Integer(1)/Integer(5))*V, V) >>> T.gram_matrix_bilinear() [1/5 0 0] [ 0 1/5 0] [ 0 0 1/5]
- gram_matrix_quadratic()[source]¶
The Gram matrix of the quadratic form with respect to the generators.
OUTPUT:
a rational matrix
Gq
withGq[i,j] = gens[i]*gens[j]
andG[i,i] = gens[i].q()
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: D4_gram = Matrix(ZZ, [[2,0,0,-1],[0,2,0,-1],[0,0,2,-1],[-1,-1,-1,2]]) sage: D4 = FreeQuadraticModule(ZZ, 4, D4_gram) sage: D4dual = D4.span(D4_gram.inverse()) sage: discrForm = TorsionQuadraticModule(D4dual, D4) sage: discrForm.gram_matrix_quadratic() [ 1 1/2] [1/2 1] sage: discrForm.gram_matrix_bilinear() [ 0 1/2] [1/2 0]
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> D4_gram = Matrix(ZZ, [[Integer(2),Integer(0),Integer(0),-Integer(1)],[Integer(0),Integer(2),Integer(0),-Integer(1)],[Integer(0),Integer(0),Integer(2),-Integer(1)],[-Integer(1),-Integer(1),-Integer(1),Integer(2)]]) >>> D4 = FreeQuadraticModule(ZZ, Integer(4), D4_gram) >>> D4dual = D4.span(D4_gram.inverse()) >>> discrForm = TorsionQuadraticModule(D4dual, D4) >>> discrForm.gram_matrix_quadratic() [ 1 1/2] [1/2 1] >>> discrForm.gram_matrix_bilinear() [ 0 1/2] [1/2 0]
- is_genus(signature_pair, even=True)[source]¶
Return
True
if there is a lattice with this signature and discriminant form.Todo
implement the same for odd lattices
INPUT:
signature_pair
– tuple of nonnegative integers(s_plus, s_minus)
even
– boolean (default:True
)
EXAMPLES:
sage: L3 = IntegralLattice(3 * Matrix(ZZ, 2, [2,1,1,2])) sage: L = IntegralLattice("D4").direct_sum(L3) # needs sage.combinat sage: D = L.discriminant_group() # needs sage.combinat sage: D.is_genus((6,0)) # needs sage.combinat True
>>> from sage.all import * >>> L3 = IntegralLattice(Integer(3) * Matrix(ZZ, Integer(2), [Integer(2),Integer(1),Integer(1),Integer(2)])) >>> L = IntegralLattice("D4").direct_sum(L3) # needs sage.combinat >>> D = L.discriminant_group() # needs sage.combinat >>> D.is_genus((Integer(6),Integer(0))) # needs sage.combinat True
Let us see if there is a lattice in the genus defined by the same discriminant form but with a different signature:
sage: D.is_genus((4,2)) # needs sage.combinat False sage: D.is_genus((16,2)) # needs sage.combinat True
>>> from sage.all import * >>> D.is_genus((Integer(4),Integer(2))) # needs sage.combinat False >>> D.is_genus((Integer(16),Integer(2))) # needs sage.combinat True
- normal_form(partial=False)[source]¶
Return the normal form of this torsion quadratic module.
Two torsion quadratic modules are isomorphic if and only if they have the same value modules and the same normal form.
A torsion quadratic module \((T,q)\) with values in \(\QQ/n\ZZ\) is in normal form if the rescaled quadratic module \((T, q/n)\) with values in \(\QQ/\ZZ\) is in normal form.
For the definition of normal form see [MirMor2009] IV Definition 4.6. Below are some of its properties. Let \(p\) be odd and \(u\) be the smallest non-square modulo \(p\). The normal form is a diagonal matrix with diagonal entries either \(p^n\) or \(u p^n\).
If \(p = 2\) is even, then the normal form consists of \(1 \times 1\) blocks of the form
\[(0), \quad 2^n(1),\quad 2^n(3),\quad 2^n(5) ,\quad 2^n(7)\]or of \(2 \times 2\) blocks of the form
\[\begin{split}2^n \left(\begin{matrix} 2 & 1\\ 1 & 2 \end{matrix}\right), \quad 2^n \left(\begin{matrix} 0 & 1\\ 1 & 0 \end{matrix}\right).\end{split}\]The blocks are ordered by their valuation.
INPUT:
partial
– boolean (default:False
); return only a partial normal form. It is not unique but still useful to extract invariants.
OUTPUT: a torsion quadratic module
EXAMPLES:
sage: L1 = IntegralLattice(matrix([[-2,0,0], [0,1,0], [0,0,4]])) sage: L1.discriminant_group().normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] [ 0 1/4] sage: L2 = IntegralLattice(matrix([[-2,0,0], [0,1,0], [0,0,-4]])) sage: L2.discriminant_group().normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] [ 0 1/4]
>>> from sage.all import * >>> L1 = IntegralLattice(matrix([[-Integer(2),Integer(0),Integer(0)], [Integer(0),Integer(1),Integer(0)], [Integer(0),Integer(0),Integer(4)]])) >>> L1.discriminant_group().normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] [ 0 1/4] >>> L2 = IntegralLattice(matrix([[-Integer(2),Integer(0),Integer(0)], [Integer(0),Integer(1),Integer(0)], [Integer(0),Integer(0),-Integer(4)]])) >>> L2.discriminant_group().normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4) Gram matrix of the quadratic form with values in Q/Z: [1/2 0] [ 0 1/4]
We check that Issue #24864 is fixed:
sage: L1 = IntegralLattice(matrix([[-4,0,0], [0,4,0], [0,0,-2]])) sage: AL1 = L1.discriminant_group() sage: L2 = IntegralLattice(matrix([[-4,0,0], [0,-4,0], [0,0,2]])) sage: AL2 = L2.discriminant_group() sage: AL1.normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: [1/2 0 0] [ 0 1/4 0] [ 0 0 5/4] sage: AL2.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: [1/2 0 0] [ 0 1/4 0] [ 0 0 5/4]
>>> from sage.all import * >>> L1 = IntegralLattice(matrix([[-Integer(4),Integer(0),Integer(0)], [Integer(0),Integer(4),Integer(0)], [Integer(0),Integer(0),-Integer(2)]])) >>> AL1 = L1.discriminant_group() >>> L2 = IntegralLattice(matrix([[-Integer(4),Integer(0),Integer(0)], [Integer(0),-Integer(4),Integer(0)], [Integer(0),Integer(0),Integer(2)]])) >>> AL2 = L2.discriminant_group() >>> AL1.normal_form() # needs sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: [1/2 0 0] [ 0 1/4 0] [ 0 0 5/4] >>> AL2.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (2, 4, 4) Gram matrix of the quadratic form with values in Q/2Z: [1/2 0 0] [ 0 1/4 0] [ 0 0 5/4]
Some exotic cases:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: D4_gram = Matrix(ZZ, 4, 4,[2,0,0,-1, 0,2,0,-1, 0,0,2,-1, -1,-1,-1,2]) sage: D4 = FreeQuadraticModule(ZZ, 4, D4_gram) sage: D4dual = D4.span(D4_gram.inverse()) sage: T = TorsionQuadraticModule((1/6)*D4dual, D4); T Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/18 1/12 5/36 1/36] [ 1/12 1/6 1/36 1/9] [ 5/36 1/36 1/36 11/72] [ 1/36 1/9 11/72 1/36] sage: T.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/6 1/12 0 0 0 0 0 0] [1/12 1/6 0 0 0 0 0 0] [ 0 0 1/12 1/24 0 0 0 0] [ 0 0 1/24 1/12 0 0 0 0] [ 0 0 0 0 1/9 0 0 0] [ 0 0 0 0 0 1/9 0 0] [ 0 0 0 0 0 0 1/9 0] [ 0 0 0 0 0 0 0 1/9]
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> D4_gram = Matrix(ZZ, Integer(4), Integer(4),[Integer(2),Integer(0),Integer(0),-Integer(1), Integer(0),Integer(2),Integer(0),-Integer(1), Integer(0),Integer(0),Integer(2),-Integer(1), -Integer(1),-Integer(1),-Integer(1),Integer(2)]) >>> D4 = FreeQuadraticModule(ZZ, Integer(4), D4_gram) >>> D4dual = D4.span(D4_gram.inverse()) >>> T = TorsionQuadraticModule((Integer(1)/Integer(6))*D4dual, D4); T Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/18 1/12 5/36 1/36] [ 1/12 1/6 1/36 1/9] [ 5/36 1/36 1/36 11/72] [ 1/36 1/9 11/72 1/36] >>> T.normal_form() # needs sage.libs.pari sage.rings.padics Finite quadratic module over Integer Ring with invariants (6, 6, 12, 12) Gram matrix of the quadratic form with values in Q/(1/3)Z: [ 1/6 1/12 0 0 0 0 0 0] [1/12 1/6 0 0 0 0 0 0] [ 0 0 1/12 1/24 0 0 0 0] [ 0 0 1/24 1/12 0 0 0 0] [ 0 0 0 0 1/9 0 0 0] [ 0 0 0 0 0 1/9 0 0] [ 0 0 0 0 0 0 1/9 0] [ 0 0 0 0 0 0 0 1/9]
- orthogonal_group(gens=None, check=False)[source]¶
Orthogonal group of the associated torsion quadratic form.
Warning
This is can be smaller than the orthogonal group of the bilinear form.
INPUT:
gens
– a list of generators, for instance square matrices, something that acts onself
, or an automorphism of the underlying abelian groupcheck
– perform additional checks on the generators
EXAMPLES:
You can provide generators to obtain a subgroup of the full orthogonal group:
sage: D = TorsionQuadraticForm(matrix.identity(2)/2) sage: f = matrix(2, [0,1,1,0]) sage: D.orthogonal_group(gens=[f]).order() # needs sage.groups 2
>>> from sage.all import * >>> D = TorsionQuadraticForm(matrix.identity(Integer(2))/Integer(2)) >>> f = matrix(Integer(2), [Integer(0),Integer(1),Integer(1),Integer(0)]) >>> D.orthogonal_group(gens=[f]).order() # needs sage.groups 2
If no generators are given a slow brute force approach is used to calculate the full orthogonal group:
sage: D = TorsionQuadraticForm(matrix.identity(3)/2) sage: OD = D.orthogonal_group() # needs sage.groups sage: OD.order() # needs sage.groups 6 sage: fd = D.hom([D.1, D.0, D.2]) # needs sage.symbolic sage: OD(fd) # needs sage.groups sage.symbolic [0 1 0] [1 0 0] [0 0 1]
>>> from sage.all import * >>> D = TorsionQuadraticForm(matrix.identity(Integer(3))/Integer(2)) >>> OD = D.orthogonal_group() # needs sage.groups >>> OD.order() # needs sage.groups 6 >>> fd = D.hom([D.gen(1), D.gen(0), D.gen(2)]) # needs sage.symbolic >>> OD(fd) # needs sage.groups sage.symbolic [0 1 0] [1 0 0] [0 0 1]
We compute the kernel of the action of the orthogonal group of \(L\) on the discriminant group:
sage: # needs sage.combinat sage.groups sage: L = IntegralLattice('A4') sage: O = L.orthogonal_group() sage: D = L.discriminant_group() sage: Obar = D.orthogonal_group(O.gens()) sage: O.order() 240 sage: Obar.order() 2 sage: phi = O.hom(Obar.gens()) sage: phi.kernel().order() 120
>>> from sage.all import * >>> # needs sage.combinat sage.groups >>> L = IntegralLattice('A4') >>> O = L.orthogonal_group() >>> D = L.discriminant_group() >>> Obar = D.orthogonal_group(O.gens()) >>> O.order() 240 >>> Obar.order() 2 >>> phi = O.hom(Obar.gens()) >>> phi.kernel().order() 120
- orthogonal_submodule_to(S)[source]¶
Return the submodule orthogonal to
S
.INPUT:
S
– a submodule, list, or tuple of generators
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeModule(ZZ, 10) sage: T = TorsionQuadraticModule(V, 3*V) sage: S = T.submodule(T.gens()[:5]) sage: O = T.orthogonal_submodule_to(S) sage: O Finite quadratic module over Integer Ring with invariants (3, 3, 3, 3, 3) Gram matrix of the quadratic form with values in Q/3Z: [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] sage: O.V() + S.V() == T.V() True
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = FreeModule(ZZ, Integer(10)) >>> T = TorsionQuadraticModule(V, Integer(3)*V) >>> S = T.submodule(T.gens()[:Integer(5)]) >>> O = T.orthogonal_submodule_to(S) >>> O Finite quadratic module over Integer Ring with invariants (3, 3, 3, 3, 3) Gram matrix of the quadratic form with values in Q/3Z: [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] >>> O.V() + S.V() == T.V() True
- primary_part(m)[source]¶
Return the
m
-primary part of this torsion quadratic module as a submodule.INPUT:
m
– integer
OUTPUT: a submodule
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: T = TorsionQuadraticModule((1/6)*ZZ^3, ZZ^3); T Finite quadratic module over Integer Ring with invariants (6, 6, 6) Gram matrix of the quadratic form with values in Q/(1/3)Z: [1/36 0 0] [ 0 1/36 0] [ 0 0 1/36] sage: T.primary_part(2) Finite quadratic module over Integer Ring with invariants (2, 2, 2) Gram matrix of the quadratic form with values in Q/(1/3)Z: [1/4 0 0] [ 0 1/4 0] [ 0 0 1/4]
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> T = TorsionQuadraticModule((Integer(1)/Integer(6))*ZZ**Integer(3), ZZ**Integer(3)); T Finite quadratic module over Integer Ring with invariants (6, 6, 6) Gram matrix of the quadratic form with values in Q/(1/3)Z: [1/36 0 0] [ 0 1/36 0] [ 0 0 1/36] >>> T.primary_part(Integer(2)) Finite quadratic module over Integer Ring with invariants (2, 2, 2) Gram matrix of the quadratic form with values in Q/(1/3)Z: [1/4 0 0] [ 0 1/4 0] [ 0 0 1/4]
- submodule_with_gens(gens)[source]¶
Return a submodule with generators given by
gens
.INPUT:
gens
– list of generators that convert intoself
OUTPUT: a submodule with the specified generators
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeQuadraticModule(ZZ, 3, matrix.identity(3)*10) sage: T = TorsionQuadraticModule((1/10)*V, V) sage: g = T.gens() sage: new_gens = [2*g[0], 5*g[0]] sage: T.submodule_with_gens(new_gens) Finite quadratic module over Integer Ring with invariants (10,) Gram matrix of the quadratic form with values in Q/2Z: [2/5 0] [ 0 1/2]
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = FreeQuadraticModule(ZZ, Integer(3), matrix.identity(Integer(3))*Integer(10)) >>> T = TorsionQuadraticModule((Integer(1)/Integer(10))*V, V) >>> g = T.gens() >>> new_gens = [Integer(2)*g[Integer(0)], Integer(5)*g[Integer(0)]] >>> T.submodule_with_gens(new_gens) Finite quadratic module over Integer Ring with invariants (10,) Gram matrix of the quadratic form with values in Q/2Z: [2/5 0] [ 0 1/2]
The generators do not need to be independent:
sage: new_gens = [g[0], 2*g[1], g[0], g[1]] sage: T.submodule_with_gens(new_gens) Finite quadratic module over Integer Ring with invariants (10, 10) Gram matrix of the quadratic form with values in Q/2Z: [1/10 0 1/10 0] [ 0 2/5 0 1/5] [1/10 0 1/10 0] [ 0 1/5 0 1/10]
>>> from sage.all import * >>> new_gens = [g[Integer(0)], Integer(2)*g[Integer(1)], g[Integer(0)], g[Integer(1)]] >>> T.submodule_with_gens(new_gens) Finite quadratic module over Integer Ring with invariants (10, 10) Gram matrix of the quadratic form with values in Q/2Z: [1/10 0 1/10 0] [ 0 2/5 0 1/5] [1/10 0 1/10 0] [ 0 1/5 0 1/10]
- twist(s)[source]¶
Return the torsion quadratic module with quadratic form scaled by
s
.If the old form was defined modulo \(n\), then the new form is defined modulo \(n s\).
INPUT:
s
– a rational number
EXAMPLES:
sage: q = TorsionQuadraticForm(matrix.diagonal([3/9, 1/9])) sage: q.twist(-1) Finite quadratic module over Integer Ring with invariants (3, 9) Gram matrix of the quadratic form with values in Q/Z: [2/3 0] [ 0 8/9]
>>> from sage.all import * >>> q = TorsionQuadraticForm(matrix.diagonal([Integer(3)/Integer(9), Integer(1)/Integer(9)])) >>> q.twist(-Integer(1)) Finite quadratic module over Integer Ring with invariants (3, 9) Gram matrix of the quadratic form with values in Q/Z: [2/3 0] [ 0 8/9]
This form is defined modulo \(3\):
sage: q.twist(3) Finite quadratic module over Integer Ring with invariants (3, 9) Gram matrix of the quadratic form with values in Q/3Z: [ 1 0] [ 0 1/3]
>>> from sage.all import * >>> q.twist(Integer(3)) Finite quadratic module over Integer Ring with invariants (3, 9) Gram matrix of the quadratic form with values in Q/3Z: [ 1 0] [ 0 1/3]
The next form is defined modulo \(4\):
sage: q.twist(4) Finite quadratic module over Integer Ring with invariants (3, 9) Gram matrix of the quadratic form with values in Q/4Z: [4/3 0] [ 0 4/9]
>>> from sage.all import * >>> q.twist(Integer(4)) Finite quadratic module over Integer Ring with invariants (3, 9) Gram matrix of the quadratic form with values in Q/4Z: [4/3 0] [ 0 4/9]
- value_module()[source]¶
Return \(\QQ / m\ZZ\) with \(m = (V, W)\).
This is where the inner product takes values.
EXAMPLES:
sage: A2 = Matrix(ZZ, 2, 2, [2,-1,-1,2]) sage: L = IntegralLattice(2*A2) sage: D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3] sage: D.value_module() Q/Z
>>> from sage.all import * >>> A2 = Matrix(ZZ, Integer(2), Integer(2), [Integer(2),-Integer(1),-Integer(1),Integer(2)]) >>> L = IntegralLattice(Integer(2)*A2) >>> D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3] >>> D.value_module() Q/Z
- value_module_qf()[source]¶
Return \(\QQ / n\ZZ\) with \(n\ZZ = (V,W) + \ZZ \{ (w,w) | w \in W \}\).
This is where the torsion quadratic form takes values.
EXAMPLES:
sage: A2 = Matrix(ZZ, 2, 2, [2,-1,-1,2]) sage: L = IntegralLattice(2 * A2) sage: D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3] sage: D.value_module_qf() Q/2Z
>>> from sage.all import * >>> A2 = Matrix(ZZ, Integer(2), Integer(2), [Integer(2),-Integer(1),-Integer(1),Integer(2)]) >>> L = IntegralLattice(Integer(2) * A2) >>> D = L.discriminant_group(); D Finite quadratic module over Integer Ring with invariants (2, 6) Gram matrix of the quadratic form with values in Q/2Z: [ 1 1/2] [1/2 1/3] >>> D.value_module_qf() Q/2Z
- class sage.modules.torsion_quadratic_module.TorsionQuadraticModuleElement(parent, x, check=True)[source]¶
Bases:
FGP_Element
An element of a torsion quadratic module.
INPUT:
parent
– parentx
– element ofparent.V()
check
– boolean (default:True
)
- b(other)[source]¶
Compute the inner product of two elements.
OUTPUT:
an element of \(\QQ / m\ZZ\) with \(m\ZZ = (V, W)\)
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = (1/2)*ZZ^2; W = ZZ^2 sage: T = TorsionQuadraticModule(V, W) sage: g = T.gens() sage: x = g[0]; x (1, 0) sage: y = g[0] + g[1] sage: x*y 1/4
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = (Integer(1)/Integer(2))*ZZ**Integer(2); W = ZZ**Integer(2) >>> T = TorsionQuadraticModule(V, W) >>> g = T.gens() >>> x = g[Integer(0)]; x (1, 0) >>> y = g[Integer(0)] + g[Integer(1)] >>> x*y 1/4
The inner product has further aliases:
sage: x.inner_product(y) 1/4 sage: x.b(y) 1/4
>>> from sage.all import * >>> x.inner_product(y) 1/4 >>> x.b(y) 1/4
- inner_product(other)[source]¶
Compute the inner product of two elements.
OUTPUT:
an element of \(\QQ / m\ZZ\) with \(m\ZZ = (V, W)\)
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = (1/2)*ZZ^2; W = ZZ^2 sage: T = TorsionQuadraticModule(V, W) sage: g = T.gens() sage: x = g[0]; x (1, 0) sage: y = g[0] + g[1] sage: x*y 1/4
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> V = (Integer(1)/Integer(2))*ZZ**Integer(2); W = ZZ**Integer(2) >>> T = TorsionQuadraticModule(V, W) >>> g = T.gens() >>> x = g[Integer(0)]; x (1, 0) >>> y = g[Integer(0)] + g[Integer(1)] >>> x*y 1/4
The inner product has further aliases:
sage: x.inner_product(y) 1/4 sage: x.b(y) 1/4
>>> from sage.all import * >>> x.inner_product(y) 1/4 >>> x.b(y) 1/4
- q()[source]¶
Compute the quadratic product of
self
.OUTPUT:
an element of \(\QQ / n\ZZ\) where \(n\ZZ = 2(V,W) + \ZZ \{ (w,w) | w \in W \}\)
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: W = FreeQuadraticModule(ZZ, 2, 2*matrix.identity(2)) sage: V = (1/2) * W sage: T = TorsionQuadraticModule(V, W) sage: x = T.gen(0) sage: x (1, 0) sage: x.quadratic_product() 1/2 sage: x.quadratic_product().parent() Q/2Z sage: x*x 1/2 sage: (x*x).parent() Q/Z
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> W = FreeQuadraticModule(ZZ, Integer(2), Integer(2)*matrix.identity(Integer(2))) >>> V = (Integer(1)/Integer(2)) * W >>> T = TorsionQuadraticModule(V, W) >>> x = T.gen(Integer(0)) >>> x (1, 0) >>> x.quadratic_product() 1/2 >>> x.quadratic_product().parent() Q/2Z >>> x*x 1/2 >>> (x*x).parent() Q/Z
- quadratic_product()[source]¶
Compute the quadratic product of
self
.OUTPUT:
an element of \(\QQ / n\ZZ\) where \(n\ZZ = 2(V,W) + \ZZ \{ (w,w) | w \in W \}\)
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: W = FreeQuadraticModule(ZZ, 2, 2*matrix.identity(2)) sage: V = (1/2) * W sage: T = TorsionQuadraticModule(V, W) sage: x = T.gen(0) sage: x (1, 0) sage: x.quadratic_product() 1/2 sage: x.quadratic_product().parent() Q/2Z sage: x*x 1/2 sage: (x*x).parent() Q/Z
>>> from sage.all import * >>> from sage.modules.torsion_quadratic_module import TorsionQuadraticModule >>> W = FreeQuadraticModule(ZZ, Integer(2), Integer(2)*matrix.identity(Integer(2))) >>> V = (Integer(1)/Integer(2)) * W >>> T = TorsionQuadraticModule(V, W) >>> x = T.gen(Integer(0)) >>> x (1, 0) >>> x.quadratic_product() 1/2 >>> x.quadratic_product().parent() Q/2Z >>> x*x 1/2 >>> (x*x).parent() Q/Z