Discriminant Groups
Torsion Quadratic Modules
A torsion quadratic module is the quotient $M/N$ of two quadratic integer lattices $N \subseteq M$ in the quadratic space $(V,\Phi)$. It inherits a bilinear form
\[b: M/N \times M/N \to \mathbb{Q} / n \mathbb{Z}\]
as well as a quadratic form
\[q: M/N \to \mathbb{Q} / m \mathbb{Z}.\]
where $n \mathbb{Z} = \Phi(M,N)$ and $m \mathbb{Z} = 2n\mathbb{Z} + \sum_{x \in N} \mathbb{Z} \Phi (x,x)$.
torsion_quadratic_module
— Methodtorsion_quadratic_module(M::ZZLat, N::ZZLat; gens::Union{Nothing, Vector{<:Vector}} = nothing,
snf::Bool = true,
modulus::QQFieldElem = QQFieldElem(0),
check::Bool = true) -> TorQuadModule
Given a Z-lattice $M$ and a sublattice $N$ of $M$, return the torsion quadratic module $M/N$.
If gens
is set, the images of gens
will be used as the generators of the abelian group $M/N$.
If snf
is true
, the underlying abelian group will be in Smith normal form. Otherwise, the images of the basis of $M$ will be used as the generators.
The underlying Type
TorQuadModule
— TypeTorQuadModule
Examples
julia> A = matrix(ZZ, [[2,0,0,-1],[0,2,0,-1],[0,0,2,-1],[-1,-1,-1,2]]);
julia> L = integer_lattice(gram = A);
julia> T = Hecke.discriminant_group(L)
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: (Z/2)^2
Gram matrix of the quadratic form with values in Q/2Z
[ 1 1//2]
[1//2 1]
We represent torsion quadratic modules as quotients of $\Z$-lattices by a full rank sublattice.
We store them as a $\Z$-lattice M
together with a projection p : M -> A
onto an abelian group A
. The bilinear structure of A
is induced via p
, that is <a, b> = <p^-1(a), p^-1(a)>
with values in $\Q/n\Z$, where $n$ is the modulus and depends on the kernel of p
.
Elements of A are basically just elements of the underlying abelian group. To move between M
and A
, we use the lift
function lift : M -> A
and coercion A(m)
.
Examples
julia> R = rescale(root_lattice(:D,4),2);
julia> D = discriminant_group(R);
julia> A = abelian_group(D)
GrpAb: (Z/2)^2 x (Z/4)^2
julia> d = D[1]
[1, 0, 0, 0]
julia> d == D(A(d))
true
julia> lift(d)
4-element Vector{QQFieldElem}:
1
1
3//2
1
N.B. Since there are no elements of $\Z$-latties, we think of elements of M
as elements of the ambient vector space. Thus if v::Vector
is such an element then the coordinates with respec to the basis of M
are given by solve_left(basis_matrix(M), v)
.
Most of the functionality mirrors that of AbGrp
its elements and homomorphisms. Here we display the part that is specific to elements of torsion quadratic modules.
Attributes
abelian_group
— Methodabelian_group(T::TorQuadModule) -> GrpAbFinGen
Return the underlying abelian group of T
.
cover
— Methodcover(T::TorQuadModule) -> ZZLat
For $T=M/N$ this returns $M$.
relations
— Methodrelations(T::TorQuadModule) -> ZZLat
For $T=M/N$ this returns $N$.
value_module
— Methodvalue_module(T::TorQuadModule)
Return the value module Q/nZ
of the bilinear form of T
.
value_module_quadratic_form
— Methodvalue_module_quadratic_form(T::TorQuadModule)
Return the value module Q/mZ
of the quadratic form of T
.
gram_matrix_bilinear
— Methodgram_matrix_bilinear(T::TorQuadModule) -> QQMatrix
Return the gram matrix of the bilinear form of T
.
gram_matrix_quadratic
— Methodgram_matrix_quadratic(T::TorQuadModule) -> QQMatrix
Return the 'gram matrix' of the quadratic form of T
.
The off diagonal entries are given by the bilinear form whereas the diagonal entries are given by the quadratic form.
modulus_bilinear_form
— Methodmodulus_bilinear_form(T::TorQuadModule) -> QQFieldElem
Return the modulus of the value module of the bilinear form ofT
.
modulus_quadratic_form
— Methodmodulus_quadratic_form(T::TorQuadModule) -> QQFieldElem
Return the modulus of the value module of the quadratic form of T
.
Elements
quadratic_product
— Methodquadratic_product(a::TorQuadModuleElem)
Return the quadratic product of a
.
It is defined in terms of a representative: for $b + M \in M/N=T$ this returns $\Phi(b,b) + n \Z$..
inner_product
— Methodinner_product(a::TorQuadModuleElem, b::TorQuadModuleElem)
Return the inner product of a
and b
.
Lift to the cover
lift
— Methodlift(a::TorQuadModuleElem) -> Vector{QQFieldElem}
Lift a
to the ambient space of cover(parent(a))
.
For $a + N \in M/N$ this returns the representative $a$.
representative
— Methodrepresentative(a::TorQuadModuleElem) -> Vector{QQFieldElem}
For $a + N \in M/N$ this returns the representative $a$. An alias for lift(a)
.
Orthogonal submodules
orthogonal_submodule
— Methodorthogonal_submodule(T::TorQuadModule, S::TorQuadModule)-> TorQuadModule
Return the orthogonal submodule to the submodule S
of T
.
Isometry
is_isometric_with_isometry
— Methodis_isometric_with_isometry(T::TorQuadModule, U::TorQuadModule)
-> Bool, TorQuadModuleMor
Return whether the torsion quadratic modules T
and U
are isometric. If yes, it also returns an isometry $T \to U$.
If T
and U
are not semi-regular it requires that they both split into a direct sum of their respective quadratic radical (see radical_quadratic
).
It requires that both T
and U
have modulus 1: in case one of them do not, they should be rescaled (see rescale
).
Examples
julia> T = torsion_quadratic_module(QQ[2//3 2//3 0 0 0;
2//3 2//3 2//3 0 2//3;
0 2//3 2//3 2//3 0;
0 0 2//3 2//3 0;
0 2//3 0 0 2//3])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: (Z/3)^5
Gram matrix of the quadratic form with values in Q/2Z
[2//3 2//3 0 0 0]
[2//3 2//3 2//3 0 2//3]
[ 0 2//3 2//3 2//3 0]
[ 0 0 2//3 2//3 0]
[ 0 2//3 0 0 2//3]
julia> U = torsion_quadratic_module(QQ[4//3 0 0 0 0;
0 4//3 0 0 0;
0 0 4//3 0 0;
0 0 0 4//3 0;
0 0 0 0 4//3])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: (Z/3)^5
Gram matrix of the quadratic form with values in Q/2Z
[4//3 0 0 0 0]
[ 0 4//3 0 0 0]
[ 0 0 4//3 0 0]
[ 0 0 0 4//3 0]
[ 0 0 0 0 4//3]
julia> bool, phi = is_isometric_with_isometry(T,U)
(true, Map with following data
Domain:
=======
TorQuadModule [2//3 2//3 0 0 0; 2//3 2//3 2//3 0 2//3; 0 2//3 2//3 2//3 0; 0 0 2//3 2//3 0; 0 2//3 0 0 2//3]
Codomain:
=========
TorQuadModule [4//3 0 0 0 0; 0 4//3 0 0 0; 0 0 4//3 0 0; 0 0 0 4//3 0; 0 0 0 0 4//3])
julia> is_bijective(phi)
true
julia> T2, _ = sub(T, [-T[4], T[2]+T[3]+T[5]])
(TorQuadModule: (Z/3)^2 [2//3 1//3; 1//3 2//3], Map with following data
Domain:
=======
TorQuadModule [2//3 1//3; 1//3 2//3]
Codomain:
=========
TorQuadModule [2//3 2//3 0 0 0; 2//3 2//3 2//3 0 2//3; 0 2//3 2//3 2//3 0; 0 0 2//3 2//3 0; 0 2//3 0 0 2//3])
julia> U2, _ = sub(T, [T[4], T[2]+T[3]+T[5]])
(TorQuadModule: (Z/3)^2 [2//3 2//3; 2//3 2//3], Map with following data
Domain:
=======
TorQuadModule [2//3 2//3; 2//3 2//3]
Codomain:
=========
TorQuadModule [2//3 2//3 0 0 0; 2//3 2//3 2//3 0 2//3; 0 2//3 2//3 2//3 0; 0 0 2//3 2//3 0; 0 2//3 0 0 2//3])
julia> bool, phi = is_isometric_with_isometry(U2, T2)
(true, Map with following data
Domain:
=======
TorQuadModule [2//3 2//3; 2//3 2//3]
Codomain:
=========
TorQuadModule [2//3 1//3; 1//3 2//3])
julia> is_bijective(phi)
true
is_anti_isometric_with_anti_isometry
— Methodis_anti_isometric_with_anti_isometry(T::TorQuadModule, U::TorQuadModule)
-> Bool, TorQuadModuleMor
Return whether there exists an anti-isometry between the torsion quadratic modules T
and U
. If yes, it returns such an anti-isometry $T \to U$.
If T
and U
are not semi-regular it requires that they both split into a direct sum of their respective quadratic radical (see radical_quadratic
).
It requires that both T
and U
have modulus 1: in case one of them do not, they should be rescaled (see rescale
).
Examples
julia> T = torsion_quadratic_module(QQ[4//5;])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: Z/5
Gram matrix of the quadratic form with values in Q/2Z
[4//5]
julia> bool, phi = is_anti_isometric_with_anti_isometry(T, T)
(true, Map with following data
Domain:
=======
TorQuadModule [4//5]
Codomain:
=========
TorQuadModule [4//5])
julia> a = gens(T)[1];
julia> a*a == -phi(a)*phi(a)
true
julia> G = matrix(FlintQQ, 6, 6 , [3 3 0 0 0 0;
3 3 3 0 3 0;
0 3 3 3 0 0;
0 0 3 3 0 0;
0 3 0 0 3 0;
0 0 0 0 0 10]);
julia> V = quadratic_space(QQ, G);
julia> B = matrix(QQ, 6, 6 , [1 0 0 0 0 0;
0 1//3 1//3 2//3 1//3 0;
0 0 1 0 0 0;
0 0 0 1 0 0;
0 0 0 0 1 0;
0 0 0 0 0 1//5]);
julia> M = lattice(V, B);
julia> B2 = matrix(FlintQQ, 6, 6 , [ 1 0 -1 1 0 0;
0 0 1 -1 0 0;
-1 1 1 -1 -1 0;
1 -1 -1 2 1 0;
0 0 -1 1 1 0;
0 0 0 0 0 1]);
julia> N = lattice(V, B2);
julia> T = torsion_quadratic_module(M, N)
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: Z/15
Gram matrix of the quadratic form with values in Q/Z
[3//5]
julia> bool, phi = is_anti_isometric_with_anti_isometry(T,T)
(true, Map with following data
Domain:
=======
TorQuadModule [3//5]
Codomain:
=========
TorQuadModule [3//5])
julia> a = gens(T)[1];
julia> a*a == -phi(a)*phi(a)
true
Primary and elementary modules
is_primary_with_prime(T::TorQuadModule)
is_primary(T::TorQuadModule, p::Union{Integer, ZZRingElem})
is_elementary_with_prime(T::TorQuadModule)
is_elementary(T::TorQuadModule, p::Union{Integer, ZZRingElem})
Smith normal form
snf(T::TorQuadModule)
is_snf(T::TorQuadModule)
Discriminant Groups
See V. V. Nikulin (1979) for the general theory of discriminant groups. They are particularly useful to work with primitive embeddings of integral integer quadratic lattices.
From a lattice
discriminant_group
— Methoddiscriminant_group(L::ZZLat) -> TorQuadModule
Return the discriminant group of L
.
The discriminant group of an integral lattice L
is the finite abelian group D = dual(L)/L
.
It comes equipped with the discriminant bilinear form
\[D \times D \to \Q / \Z \qquad (x,y) \mapsto \Phi(x,y) + \Z.\]
If L
is even, then the discriminant group is equipped with the discriminant quadratic form $D \to \Q / 2 \Z, x \mapsto \Phi(x,x) + 2\Z$.
From a Matrix
torsion_quadratic_module
— Methodtorsion_quadratic_module(q::QQMatrix) -> TorQuadModule
Return a torsion quadratic module with gram matrix given by q
and value module Q/Z
. If all the diagonal entries of q
have: either even numerator or even denominator, then the value module of the quadratic form is Q/2Z
Example
julia> torsion_quadratic_module(QQ[1//6;])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: Z/6
Gram matrix of the quadratic form with values in Q/2Z
[1//6]
julia> torsion_quadratic_module(QQ[1//2;])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: Z/2
Gram matrix of the quadratic form with values in Q/2Z
[1//2]
julia> torsion_quadratic_module(QQ[3//2;])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: Z/2
Gram matrix of the quadratic form with values in Q/2Z
[3//2]
julia> torsion_quadratic_module(QQ[1//3;])
Finite quadratic module over Integer Ring with underlying abelian group
GrpAb: Z/3
Gram matrix of the quadratic form with values in Q/Z
[1//3]
Rescaling the form
rescale
— Methodrescale(T::TorQuadModule, k::RingElement) -> TorQuadModule
Return the torsion quadratic module with quadratic form scaled by $k$, where k is a non-zero rational number. If the old form was defined modulo n
, then the new form is defined modulo n k
.
Invariants
is_degenerate
— Methodis_degenerate(T::TorQuadModule) -> Bool
Return true if the underlying bilinear form is degenerate.
is_semi_regular
— Methodis_semi_regular(T::TorQuadModule) -> Bool
Return whether T
is semi-regular, that is its quadratic radical is trivial (see radical_quadratic
).
radical_bilinear
— Methodradical_bilinear(T::TorQuadModule) -> TorQuadModule, TorQuadModuleMor
Return the radical \{x \in T | b(x,T) = 0\}
of the bilinear form b
on T
.
radical_quadratic
— Methodradical_quadratic(T::TorQuadModule) -> TorQuadModule, TorQuadModuleMor
Return the radical \{x \in T | b(x,T) = 0 and q(x)=0\}
of the quadratic form q
on T
.
normal_form
— Methodnormal_form(T::TorQuadModule; partial=false) -> TorQuadModule, TorQuadModuleMor
Return the normal form N
of the given torsion quadratic module T
along with the projection T -> N
.
Let K
be the radical of the quadratic form of T
. Then N = T/K
is half-regular. Two half-regular torsion quadratic modules are isometric if and only if they have equal normal forms.
Genus
genus
— Methodgenus(T::TorQuadModule, signature_pair::Tuple{Int, Int}) -> ZZGenus
Return the genus of an integer lattice with discriminant group T
and the given signature_pair
. If no such genus exists, raise an error.
Reference
V. V. Nikulin (1979) Corollary 1.9.4 and 1.16.3.
brown_invariant
— Methodbrown_invariant(self::TorQuadModule) -> Nemo.zzModRingElem
Return the Brown invariant of this torsion quadratic form.
Let (D,q)
be a torsion quadratic module with values in Q / 2Z
. The Brown invariant Br(D,q) in Z/8Z
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.
Examples
julia> L = integer_lattice(gram=matrix(ZZ, [[2,-1,0,0],[-1,2,-1,-1],[0,-1,2,0],[0,-1,0,2]]));
julia> T = Hecke.discriminant_group(L);
julia> brown_invariant(T)
4
is_genus
— Methodis_genus(T::TorQuadModule, signature_pair::Tuple{Int, Int}) -> Bool
Return if there is an integral lattice with this signature and discriminant form.
Categorical constructions
direct_sum
— Methoddirect_sum(x::Vararg{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMor}
direct_sum(x::Vector{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMor}
Given a collection of torsion quadratic modules $T_1, \ldots, T_n$, return their direct sum $T := T_1\oplus \ldots \oplus T_n$, together with the injections $T_i \to T$.
For objects of type TorQuadModule
, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain T
as a direct product with the projections $T \to T_i$, one should call direct_product(x)
. If one wants to obtain T
as a biproduct with the injections $T_i \to T$ and the projections $T \to T_i$, one should call biproduct(x)
.
direct_product
— Methoddirect_product(x::Vararg{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMor}
direct_product(x::Vector{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMor}
Given a collection of torsion quadratic modules $T_1, \ldots, T_n$, return their direct product $T := T_1\times \ldots \times T_n$, together with the projections $T \to T_i$.
For objects of type TorQuadModule
, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain T
as a direct sum with the inctions $T_i \to T$, one should call direct_sum(x)
. If one wants to obtain T
as a biproduct with the injections $T_i \to T$ and the projections $T \to T_i$, one should call biproduct(x)
.
biproduct
— Methodbiproduct(x::Vararg{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMor}, Vector{TorQuadModuleMor}
biproduct(x::Vector{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMor}, Vector{TorQuadModuleMor}
Given a collection of torsion quadratic modules $T_1, \ldots, T_n$, return their biproduct $T := T_1\oplus \ldots \oplus T_n$, together with the injections $T_i \to T$ and the projections $T \to T_i$.
For objects of type TorQuadModule
, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain T
as a direct sum with the inctions $T_i \to T$, one should call direct_sum(x)
. If one wants to obtain T
as a direct product with the projections $T \to T_i$, one should call direct_product(x)
.