Discriminant Groups
Torsion Quadratic Modules
A torsion quadratic module is the quotient of two quadratic integer lattices in the quadratic space . It inherits a bilinear form
as well as a quadratic form
where and .
#
torsion_quadratic_module — Method.
torsion_quadratic_module(M::ZLat, N::ZLat; gens::Union{Nothing, Vector{<:Vector}} = nothing,
snf::Bool = true,
modulus::fmpq = fmpq(0),
check::Bool = true)
Given a Z-lattice and a sublattice of , return the torsion quadratic module .
If gens is set, the images of gens will be used as the generators of the abelian group .
If snf is true, the underlying abelian group will be in Smith normal form. Otherwise, the images of the basis of will be used as the generators.
The underlying Type
#
TorQuadMod — Type.
TorQuadMod
Example:
julia> A = matrix(ZZ, [[2,0,0,-1],[0,2,0,-1],[0,0,2,-1],[-1,-1,-1,2]]);
julia> L = Zlattice(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 -lattices by a full rank sublattice.
We store them as a -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 , where 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{fmpq}:
1
1
3//2
1
N.B. Since there are no elements of -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 — Method.
abelian_group(T::TorQuadMod) -> GrpAbFinGen
Return the underlying abelian group of T.
#
cover — Method.
cover(T::TorQuadMod) -> ZLat
For this returns .
#
relations — Method.
relations(T::TorQuadMod) -> ZLat
For this returns .
#
value_module — Method.
value_module(T::TorQuadMod)
Return the value module Q/nZ of the bilinear form of T.
#
value_module_quadratic_form — Method.
value_module_quadratic_form(T::TorQuadMod)
Return the value module Q/mZ of the quadratic form of T.
#
gram_matrix_bilinear — Method.
gram_matrix_bilinear(T::TorQuadMod) -> fmpq_mat
Return the gram matrix of the bilinear form of T.
#
gram_matrix_quadratic — Method.
gram_matrix_quadratic(T::TorQuadMod) -> fmpq_mat
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 — Method.
modulus_bilinear_form(T::TorQuadMod) -> fmpq
Return the modulus of the value module of the bilinear form ofT.
#
modulus_quadratic_form — Method.
modulus_quadratic_form(T::TorQuadMod) -> fmpq
Return the modulus of the value module of the quadratic form of T.
Elements
#
quadratic_product — Method.
quadratic_product(a::TorQuadModElem)
Return the quadratic product of a.
It is defined in terms of a representative: for this returns ..
#
inner_product — Method.
inner_product(a::TorQuadModElem, b::TorQuadModElem)
Return the inner product of a and b.
Lift to the cover
#
lift — Method.
lift(a::TorQuadModElem) -> Vector{fmpq}
Lift a to the ambient space of cover(parent(a)).
For this returns the representative .
#
representative — Method.
representative(a::TorQuadModElem) -> Vector{fmpq}
For this returns the representative . An alias for lift(a).
Orthogonal submodules
#
orthogonal_submodule — Method.
orthogonal_submodule(T::TorQuadMod, S::TorQuadMod)-> TorQuadMod
Return the orthogonal submodule to the submodule S of T.
Isometry
#
is_isometric_with_isometry — Method.
is_isometric_with_isometry(T::TorQuadMod, U::TorQuadMod)
-> Bool, TorQuadModMor
Return whether the torsion quadratic modules T and U are isometric. If yes, it also returns an isometry .
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:
=======
TorQuadMod [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:
=========
TorQuadMod [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]])
(TorQuadMod: (Z/3)^2 [2//3 1//3; 1//3 2//3], Map with following data
Domain:
=======
TorQuadMod [2//3 1//3; 1//3 2//3]
Codomain:
=========
TorQuadMod [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]])
(TorQuadMod: (Z/3)^2 [2//3 2//3; 2//3 2//3], Map with following data
Domain:
=======
TorQuadMod [2//3 2//3; 2//3 2//3]
Codomain:
=========
TorQuadMod [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:
=======
TorQuadMod [2//3 2//3; 2//3 2//3]
Codomain:
=========
TorQuadMod [2//3 1//3; 1//3 2//3])
julia> is_bijective(phi)
true
#
is_anti_isometric_with_anti_isometry — Method.
is_anti_isometric_with_anti_isometry(T::TorQuadMod, U::TorQuadMod)
-> Bool, TorQuadModMor
Return whether there exists an anti-isometry between the torsion quadratic modules T and U. If yes, it returns such an anti-isometry .
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:
=======
TorQuadMod [4//5]
Codomain:
=========
TorQuadMod [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:
=======
TorQuadMod [3//5]
Codomain:
=========
TorQuadMod [3//5])
julia> a = gens(T)[1];
julia> a*a == -phi(a)*phi(a)
true
Primary and elementary modules
is_primary_with_prime(T::TorQuadMod)
is_primary(T::TorQuadMod, p::Union{Integer, fmpz})
is_elementary_with_prime(T::TorQuadMod)
is_elementary(T::TorQuadMod, p::Union{Integer, fmpz})
Smith normal form
snf(T::TorQuadMod)
is_snf(T::TorQuadMod)
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 — Method.
discriminant_group(L::ZLat) -> TorQuadMod
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
If L is even, then the discriminant group is equipped with the discriminant quadratic form .
From a Matrix
#
torsion_quadratic_module — Method.
torsion_quadratic_module(q::fmpq_mat) -> TorQuadMod
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 — Method.
rescale(T::TorQuadMod, k::RingElement) -> TorQuadMod
Return the torsion quadratic module with quadratic form scaled by , 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 — Method.
is_degenerate(T::TorQuadMod) -> Bool
Return true if the underlying bilinear form is degenerate.
#
is_semi_regular — Method.
is_semi_regular(T::TorQuadMod) -> Bool
Return whether T is semi-regular, that is its quadratic radical is trivial (see radical_quadratic).
#
radical_bilinear — Method.
radical_bilinear(T::TorQuadMod) -> TorQuadMod, TorQuadModMor
Return the radical \{x \in T | b(x,T) = 0\} of the bilinear form b on T.
#
radical_quadratic — Method.
radical_quadratic(T::TorQuadMod) -> TorQuadMod, TorQuadModMor
Return the radical \{x \in T | b(x,T) = 0 and q(x)=0\} of the quadratic form q on T.
#
normal_form — Method.
normal_form(T::TorQuadMod; partial=false) -> TorQuadMod, TorQuadModMor
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 — Method.
genus(T::TorQuadMod, signature_pair::Tuple{Int, Int}) -> ZGenus
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 — Method.
brown_invariant(self::TorQuadMod) -> Nemo.nmod
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
The Brown invariant is additive with respect to direct sums of torsion quadratic modules.
Examples
julia> L = Zlattice(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 — Method.
is_genus(T::TorQuadMod, signature_pair::Tuple{Int, Int}) -> Bool
Return if there is an integral lattice with this signature and discriminant form.
Orthogonal sums
#
orthogonal_sum — Method.
orthogonal_sum(T::TorQuadMod, U::TorQuadMod)
-> TorQuadMod, TorQuadModMor, TorQuadModMor
Return the orthogonal direct sum S of T and U as a quotient of the direct sum of their respective covers.
It is given with the two injections and .
Note that T and U must have the same moduli, both bilinear and quadratic ones.
#
direct_sum — Method.
direct_sum(x::Vararg{TorQuadMod}) -> TorQuadMod, Vector{TorQuadModMor}, Vector{TorQuadModMor}
direct_sum(x::Vector{TorQuadMod}) -> TorQuadMod, Vector{TorQuadModMor}, Vector{TorQuadModMor}
Given a collection of torsion quadratic modules , return their complete direct sum , together with the injections and the projections .