Skip to content

Discriminant Groups

Torsion Quadratic Modules

A torsion quadratic module is the quotient M/N of two quadratic integer lattices NM in the quadratic space (V,Φ). It inherits a bilinear form

b:M/N×M/NQ/nZ

as well as a quadratic form

q:M/NQ/mZ.

where nZ=Φ(M,N) and mZ=2nZ+xNZΦ(x,x).

# torsion_quadratic_moduleMethod.
julia
torsion_quadratic_module(M::ZZLat, N::ZZLat; gens::Union{Nothing, Vector{<:Vector}} = nothing,
                                             snf::Bool = true,
                                             modulus::RationalUnion = QQFieldElem(0),
                                             modulus_qf::RationalUnion = 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.

One can decide on the modulus for the associated finite bilinear and quadratic forms by setting modulus and modulus_qf respectively to the desired values.

source


The underlying Type

# TorQuadModuleType.
julia
TorQuadModule

Examples

julia
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
Abelian group: (Z/2)^2
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[   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/nZ, 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
julia> R = rescale(root_lattice(:D,4),2);

julia> D = discriminant_group(R);

julia> A = abelian_group(D)
(Z/2)^2 x (Z/4)^2

julia> d = D[1]
Element
  of finite quadratic module: (Z/2)^2 x (Z/4)^2 -> Q/2Z
with components [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-lattices, 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(basis_matrix(M), v; side = :left).

source


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_groupMethod.
julia
abelian_group(T::TorQuadModule) -> FinGenAbGroup

Return the underlying abelian group of T.

source


# coverMethod.
julia
cover(T::TorQuadModule) -> ZZLat

For T=M/N this returns M.

source


# relationsMethod.
julia
relations(T::TorQuadModule) -> ZZLat

For T=M/N this returns N.

source


# value_moduleMethod.
julia
value_module(T::TorQuadModule) -> QmodnZ

Return the value module Q/nZ of the bilinear form of T.

source


# value_module_quadratic_formMethod.
julia
value_module_quadratic_form(T::TorQuadModule) -> QmodnZ

Return the value module Q/mZ of the quadratic form of T.

source


# gram_matrix_bilinearMethod.
julia
gram_matrix_bilinear(T::TorQuadModule) -> QQMatrix

Return the gram matrix of the bilinear form of T.

source


# gram_matrix_quadraticMethod.
julia
gram_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.

source


# modulus_bilinear_formMethod.
julia
modulus_bilinear_form(T::TorQuadModule) -> QQFieldElem

Return the modulus of the value module of the bilinear form ofT.

source


# modulus_quadratic_formMethod.
julia
modulus_quadratic_form(T::TorQuadModule) -> QQFieldElem

Return the modulus of the value module of the quadratic form of T.

source


Elements

# quadratic_productMethod.
julia
quadratic_product(a::TorQuadModuleElem) -> QmodnZElem

Return the quadratic product of a.

It is defined in terms of a representative: for b+MM/N=T, this returns Φ(b,b)+nZ.

source


# inner_productMethod.
julia
inner_product(a::TorQuadModuleElem, b::TorQuadModuleElem) -> QmodnZElem

Return the inner product of a and b.

source


Lift to the cover

# liftMethod.
julia
lift(a::TorQuadModuleElem) -> Vector{QQFieldElem}

Lift a to the ambient space of cover(parent(a)).

For a+NM/N this returns the representative a.

source


# representativeMethod.
julia
representative(a::TorQuadModuleElem) -> Vector{QQFieldElem}

For a+NM/N this returns the representative a. An alias for lift(a).

source


Orthogonal submodules

# orthogonal_submoduleMethod.
julia
orthogonal_submodule(T::TorQuadModule, S::TorQuadModule)-> TorQuadModule

Return the orthogonal submodule to the submodule S of T.

source


Isometry

# is_isometric_with_isometryMethod.
julia
is_isometric_with_isometry(T::TorQuadModule, U::TorQuadModule)
                                               -> Bool, TorQuadModuleMap

Return whether the torsion quadratic modules T and U are isometric. If yes, it also returns an isometry TU.

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
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
Abelian group: (Z/3)^5
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[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
Abelian group: (Z/3)^5
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[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: finite quadratic module -> finite quadratic module)

julia> is_bijective(phi)
true

julia> T2, _ = sub(T, [-T[4], T[2]+T[3]+T[5]])
(Finite quadratic module: (Z/3)^2 -> Q/2Z, Map: finite quadratic module -> finite quadratic module)

julia> U2, _ = sub(T, [T[4], T[2]+T[3]+T[5]])
(Finite quadratic module: (Z/3)^2 -> Q/2Z, Map: finite quadratic module -> finite quadratic module)

julia> bool, phi = is_isometric_with_isometry(U2, T2)
(true, Map: finite quadratic module -> finite quadratic module)

julia> is_bijective(phi)
true

source


# is_anti_isometric_with_anti_isometryMethod.
julia
is_anti_isometric_with_anti_isometry(T::TorQuadModule, U::TorQuadModule)
                                                 -> Bool, TorQuadModuleMap

Return whether there exists an anti-isometry between the torsion quadratic modules T and U. If yes, it returns such an anti-isometry TU.

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
julia> T = torsion_quadratic_module(QQ[4//5;])
Finite quadratic module
  over integer ring
Abelian group: Z/5
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[4//5]

julia> bool, phi = is_anti_isometric_with_anti_isometry(T, T)
(true, Map: finite quadratic module -> finite quadratic module)

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
Abelian group: Z/15
Bilinear value module: Q/Z
Quadratic value module: Q/Z
Gram matrix quadratic form:
[3//5]

julia> bool, phi = is_anti_isometric_with_anti_isometry(T,T)
(true, Map: finite quadratic module -> finite quadratic module)

julia> a = gens(T)[1];

julia> a*a == -phi(a)*phi(a)
true

source


Primary and elementary modules

# is_primary_with_primeMethod.
julia
is_primary_with_prime(T::TorQuadModule) -> Bool, ZZRingElem

Given a torsion quadratic module T, return whether the underlying (finite) abelian group of T (see abelian_group) is a p-group for some prime number p. In case it is, p is also returned as second output.

Note that in the case of trivial groups, this function returns (true, 1). If T is not primary, the second return value is -1 by default.

source


# is_primaryMethod.
julia
is_primary(T::TorQuadModule, p::Union{Integer, ZZRingElem}) -> Bool

Given a torsion quadratic module T and a prime number p, return whether the underlying (finite) abelian group of T (see abelian_group) is a p-group.

source


# is_elementary_with_primeMethod.
julia
is_elementary_with_prime(T::TorQuadModule) -> Bool, ZZRingElem

Given a torsion quadratic module T, return whether the underlying (finite) abelian group of T (see abelian_group) is an elementary p-group, for some prime number p. In case it is, p is also returned as second output.

Note that in the case of trivial groups, this function returns (true, 1). If T is not elementary, the second return value is -1 by default.

source


# is_elementaryMethod.
julia
is_elementary(T::TorQuadModule, p::Union{Integer, ZZRingElem}) -> Bool

Given a torsion quadratic module T and a prime number p, return whether the underlying (finite) abelian group of T (see abelian_group) is an elementary p-group.

source


Smith normal form

# snfMethod.
julia
snf(T::TorQuadModule) -> TorQuadModule, TorQuadModuleMap

Given a torsion quadratic module T, return a torsion quadratic module S, isometric to T, such that the underlying abelian group of S is in canonical Smith normal form. It comes with an isometry f:ST.

source


# is_snfMethod.
julia
is_snf(T::TorQuadModule) -> Bool

Given a torsion quadratic module T, return whether its underlying abelian group is in Smith normal form.

source


Discriminant Groups

See [6] 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_groupMethod.
julia
discriminant_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×DQ/Z(x,y)Φ(x,y)+Z.

If L is even, then the discriminant group is equipped with the discriminant quadratic form DQ/2Z,xΦ(x,x)+2Z.

source


From a matrix

# torsion_quadratic_moduleMethod.
julia
torsion_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
julia> torsion_quadratic_module(QQ[1//6;])
Finite quadratic module
  over integer ring
Abelian group: Z/6
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[1//6]

julia> torsion_quadratic_module(QQ[1//2;])
Finite quadratic module
  over integer ring
Abelian group: Z/2
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[1//2]

julia> torsion_quadratic_module(QQ[3//2;])
Finite quadratic module
  over integer ring
Abelian group: Z/2
Bilinear value module: Q/Z
Quadratic value module: Q/2Z
Gram matrix quadratic form:
[3//2]

julia> torsion_quadratic_module(QQ[1//3;])
Finite quadratic module
  over integer ring
Abelian group: Z/3
Bilinear value module: Q/Z
Quadratic value module: Q/Z
Gram matrix quadratic form:
[1//3]

source


Rescaling the form

# rescaleMethod.
julia
rescale(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.

source


Invariants

# is_degenerateMethod.
julia
is_degenerate(T::TorQuadModule) -> Bool

Return true if the underlying bilinear form is degenerate.

source


# is_semi_regularMethod.
julia
is_semi_regular(T::TorQuadModule) -> Bool

Return whether T is semi-regular, that is its quadratic radical is trivial (see radical_quadratic).

source


# radical_bilinearMethod.
julia
radical_bilinear(T::TorQuadModule) -> TorQuadModule, TorQuadModuleMap

Return the radical \{x \in T | b(x,T) = 0\} of the bilinear form b on T.

source


# radical_quadraticMethod.
julia
radical_quadratic(T::TorQuadModule) -> TorQuadModule, TorQuadModuleMap

Return the radical \{x \in T | b(x,T) = 0 and q(x)=0\} of the quadratic form q on T.

source


# normal_formMethod.
julia
normal_form(T::TorQuadModule; partial=false) -> TorQuadModule, TorQuadModuleMap

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.

source


Genus

# genusMethod.
julia
genus(T::TorQuadModule, signature_pair::Tuple{Int, Int};
                        parity::RationalUnion = modulus_quadratic_form(T))
                                                                -> ZZGenus

Return the genus of an integer lattice whose discriminant group has the bilinear form of T, the given signature_pair and the given parity.

The argument parity is one of the following: either parity == 1 for genera of odd lattices, or parity == 2 for even lattices. By default, parity is set to be as the parity of the quadratic form on T

If no such genus exists, raise an error.

Reference

[6] Corollary 1.9.4 and 1.16.3.

source


# brown_invariantMethod.
julia
brown_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(2πi8Br(q))=1DxDexp(iπq(x)).

The Brown invariant is additive with respect to direct sums of torsion quadratic modules.

Examples

julia
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

source


# is_genusMethod.
julia
is_genus(T::TorQuadModule, signature_pair::Tuple{Int, Int};
                           parity::RationalUnion = modulus_quadratic_form(T)) -> Bool

Return if there is an integral lattice whose discriminant form has the bilinear form of T, whose signatures match signature_pair and which is of parity parity.

The argument parity is one of the following: either parity == 1 for genera of odd lattices, or parity == 2 for even lattices. By default, parity is set to be as the parity of the quadratic form on T

source


Categorical constructions

# direct_sumMethod.
julia
direct_sum(x::Vararg{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMap}
direct_sum(x::Vector{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMap}

Given a collection of torsion quadratic modules T1,,Tn, return their direct sum T:=T1Tn, together with the injections TiT.

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 TTi, one should call direct_product(x). If one wants to obtain T as a biproduct with the injections TiT and the projections TTi, one should call biproduct(x).

source


# direct_productMethod.
julia
direct_product(x::Vararg{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMap}
direct_product(x::Vector{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMap}

Given a collection of torsion quadratic modules T1,,Tn, return their direct product T:=T1××Tn, together with the projections TTi.

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 TiT, one should call direct_sum(x). If one wants to obtain T as a biproduct with the injections TiT and the projections TTi, one should call biproduct(x).

source


# biproductMethod.
julia
biproduct(x::Vararg{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMap}, Vector{TorQuadModuleMap}
biproduct(x::Vector{TorQuadModule}) -> TorQuadModule, Vector{TorQuadModuleMap}, Vector{TorQuadModuleMap}

Given a collection of torsion quadratic modules T1,,Tn, return their biproduct T:=T1Tn, together with the injections TiT and the projections TTi.

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 TiT, one should call direct_sum(x). If one wants to obtain T as a direct product with the projections TTi, one should call direct_product(x).

source


Submodules

# submodulesMethod.
julia
submodules(T::TorQuadModule; kw...)

Return the submodules of T as an iterator. Possible keyword arguments to restrict the submodules:

  • order::Int: only submodules of order order,

  • index::Int: only submodules of index index,

  • subtype::Vector{Int}: only submodules which are isomorphic as an abelian group to abelian_group(subtype),

  • quotype::Vector{Int}: only submodules whose quotient are isomorphic as an abelian to abelian_group(quotype).

source


# stable_submodulesMethod.
julia
stable_submodules(T::TorQuadModule, act::Vector{TorQuadModuleMap}; kw...)

Return the submodules of T stable under the endomorphisms in act as an iterator. Possible keyword arguments to restrict the submodules:

  • quotype::Vector{Int}: only submodules whose quotient are isomorphic as an abelian group to abelian_group(quotype).

source