Finite \(\ZZ\)-modules with with bilinear and quadratic forms.¶
AUTHORS:
Simon Brandhorst (2017-09): First created
- sage.modules.torsion_quadratic_module.TorsionQuadraticForm(q)¶
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]
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]
- class sage.modules.torsion_quadratic_module.TorsionQuadraticModule(V, W, gens, modulus, modulus_qf)¶
Bases:
sage.modules.fg_pid.fgp_module.FGP_Module_class
,sage.structure.unique_representation.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
– bool (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) sage: 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¶
alias of
TorsionQuadraticModuleElement
- all_submodules()¶
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() sage: D.all_submodules() [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()¶
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") sage: D = L.discriminant_group() sage: D.brown_invariant() 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
- gens()¶
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))
- genus(signature_pair)¶
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: L = IntegralLattice("D4").direct_sum(IntegralLattice("A2")) sage: D = L.discriminant_group() sage: genus = D.genus(L.signature_pair()) sage: genus 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() 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) sage: DK 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)) 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)) 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()¶
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]
- gram_matrix_quadratic()¶
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]
- is_genus(signature_pair, even=True)¶
Return
True
if there is a lattice with this signature and discriminant form.Todo
implement the same for odd lattices
INPUT:
signature_pair – a tuple of non negative integers
(s_plus, s_minus)
even – bool (default:
True
)
EXAMPLES:
sage: L = IntegralLattice("D4").direct_sum(IntegralLattice(3 * Matrix(ZZ,2,[2,1,1,2]))) sage: D = L.discriminant_group() sage: D.is_genus((6,0)) 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)) False sage: D.is_genus((16,2)) True
- normal_form(partial=False)¶
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 x 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 - bool (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() 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() 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 trac ticket #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() 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() 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) sage: 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() 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)¶
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 on
self
, or an automorphism of the underlying abelian group
check
– 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() 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() sage: OD.order() 6 sage: fd = D.hom([D.1,D.0,D.2]) sage: OD(fd) [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: 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
- orthogonal_submodule_to(S)¶
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
- primary_part(m)¶
Return the
m
-primary part of this torsion quadratic module as a submodule.INPUT:
m
– an integer
OUTPUT:
a submodule
EXAMPLES:
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: T = TorsionQuadraticModule((1/6)*ZZ^3,ZZ^3) sage: 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]
- submodule_with_gens(gens)¶
Return a submodule with generators given by
gens
.INPUT:
gens
– a 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]
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]
- twist(s)¶
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]
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]
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]
- value_module()¶
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() sage: 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
- value_module_qf()¶
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() sage: 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
- class sage.modules.torsion_quadratic_module.TorsionQuadraticModuleElement(parent, x, check=True)¶
Bases:
sage.modules.fg_pid.fgp_element.FGP_Element
An element of a torsion quadratic module.
INPUT:
parent
– parentx
– element ofparent.V()
check
– bool (default:True
)
- b(other)¶
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] sage: y = g[0] + g[1] sage: x (1, 0) sage: x*y 1/4
The inner product has further aliases:
sage: x.inner_product(y) 1/4 sage: x.b(y) 1/4
- inner_product(other)¶
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] sage: y = g[0] + g[1] sage: x (1, 0) sage: x*y 1/4
The inner product has further aliases:
sage: x.inner_product(y) 1/4 sage: x.b(y) 1/4
- q()¶
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
- quadratic_product()¶
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