Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Finite `\ZZ`-modules with with bilinear and quadratic forms.
AUTHORS:
- Simon Brandhorst (2017-09): First created """
#***************************************************************************** # Copyright (C) 2017 Simon Brandhorst <sbrandhorst@web.de> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
r""" 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] """ raise ValueError("the input must be a square matrix") raise ValueError("the input must be a symmetric matrix")
r""" An element of a torsion quadratic module.
INPUT:
- ``parent`` -- parent - ``x`` -- element of ``parent.V()``
TESTS::
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: T = TorsionQuadraticModule(ZZ^3, 6*ZZ^3) sage: loads(dumps(T)) == T True sage: t = T.gen(0) sage: loads(dumps(t)) == t True """ r""" Initialize ``self``
EXAMPLES::
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) sage: b = V.basis() sage: W = V.span([2*b[0]+4*b[1], 9*b[0]+12*b[1], 4*b[2]]) sage: Q = TorsionQuadraticModule(V, W) sage: x = Q(b[0] - b[1]) sage: TestSuite(x).run() """
r""" 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 """
r""" 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 """
r""" 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`` -- a :class:`FreeModule` with a symmetric inner product matrix
- ``W`` -- a submodule of ``V`` of the same rank as ``V``
- ``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] """
r""" Initialize ``self``.
TESTS::
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: T = TorsionQuadraticModule(ZZ^3, 6*ZZ^3) sage: TestSuite(T).run() """ raise ValueError("modules must be of the same rank") raise NotImplementedError("only currently implemented over ZZ") raise ValueError("the cover must have a symmetric inner product")
raise ValueError("provided gens do not generate the quotient")
else: self._gens = [self(v) for v in gens]
# The inner product of two elements `b(v1+W,v2+W)` is defined `mod (V,W)` for y in W.gens()]) raise ValueError("the modulus must divide (V, W)") else: # The inner product of two elements `b(v1+W,v2+W)` is defined `mod (V,W)` for y in W.gens()])
if check: # The quadratic_product of an element `q(v+W)` is defined # `\mod 2(V,W) + ZZ\{ (w,w) | w in w\}` norm = gcd(self.W().gram_matrix().diagonal()) num = gcd(norm, 2 * self._modulus) if num / modulus_qf not in self.base_ring(): raise ValueError("the modulus_qf must divide (V, W)") self._modulus_qf = modulus_qf else: # The quadratic_product of an element `q(v+W)` is defined # `\mod 2(V,W) + ZZ\{ (w,w) | w in w\}`
r""" Return a string representation of ``self``.
EXAMPLES::
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = FreeModule(ZZ,3) sage: T = TorsionQuadraticModule(V, 5*V,modulus=1) sage: T Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/Z: [0 0 0] [0 0 0] [0 0 0] """ % (self.base_ring(),self.invariants()) + "Gram matrix of the quadratic form with values in %r:\n%r" % (self.value_module_qf(),self.gram_matrix_quadratic()) )
r""" Construct a torsion quadratic module ``V / W``.
INPUT:
- ``V`` -- an module - ``W`` -- an submodule of ``V`` over the same base ring - ``check`` -- bool (default: ``True``)
OUTPUT:
The quotient ``V / W`` as a :class:`TorsionQuadraticModule`.
EXAMPLES::
sage: from sage.modules.torsion_quadratic_module import TorsionQuadraticModule sage: V = span([[1/2,1,1], [3/2,2,1], [0,0,1]], ZZ) sage: b = V.basis() sage: W = V.span([2*b[0]+4*b[1], 9*b[0]+12*b[1], 4*b[2]]) sage: Q = TorsionQuadraticModule(V, W); Q Finite quadratic module over Integer Ring with invariants (4, 12) Gram matrix of the quadratic form with values in Q/(1/4)Z: [0 0] [0 0] sage: Q._module_constructor(V,W) Finite quadratic module over Integer Ring with invariants (4, 12) Gram matrix of the quadratic form with values in Q/(1/4)Z: [0 0] [0 0] """
def gram_matrix_bilinear(self): r""" Return the gram matrix with respect to the generators.
OUTPUT:
A rational matrix ``G`` with ``G[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] """
def gram_matrix_quadratic(self): r""" The gram matrix of the quadratic form with respect to the generators.
OUTPUT:
- a rational matrix ``Gq`` with ``Gq[i,j] = gens[i]*gens[j]`` and ``G[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] """
r""" 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)) """
r""" 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 """ S = self.submodule(S) else: raise ValueError("S must be a submodule of this module")
# Elements of the ambient module which pair integrally with self.V() # Element of the ambient module which pair in mZZ with self.V() # We have to make sure we get a submodule
r""" 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
.. MATH::
(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
.. MATH::
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).
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:`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 5/36 0 0] [5/36 1/18 5/36 5/36] [ 0 5/36 1/36 1/72] [ 0 5/36 1/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]
TESTS:
A degenerate case::
sage: T = TorsionQuadraticModule((1/6)*D4dual, D4, modulus=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/18)Z: [1/36 1/72 0 0 0 0 0 0] [1/72 1/36 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] """
# continue with the non-degenerate part else:
# the normal form is implemented for p-adic lattices # so we should work with the lattice q_p --> q_p^-1 # if we compute the inverse in the p-adics everything explodes --> go to ZZ
# the inverse is in normal form - so to get a normal form for the original one # it is enough to massage each 1x1 resp. 2x2 block.
# reattach the degenerate part
#apply U to the generators
r""" 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]
TESTS::
sage: T == T.primary_part(T.annihilator().gen()) True """
r""" Return the submodule defined by ``x``.
The modulus of the inner product is inherited from ``self``.
INPUT:
- ``x`` -- list, tuple, or FGP module
OUTPUT:
- a :class:`TorsionQuadraticModule`
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 Finite quadratic module over Integer Ring with invariants (5, 5, 5) Gram matrix of the quadratic form with values in Q/Z: [1/5 0 0] [ 0 1/5 0] [ 0 0 1/5] sage: T.submodule(T.gens()[:2]) Finite quadratic module over Integer Ring with invariants (5, 5) Gram matrix of the quadratic form with values in Q/Z: [1/5 0] [ 0 1/5] """ # We need to explicitly set the _modulus and _modulus_qf # else the modulus might increase.
r""" Return a submodule with generators given by ``gens``.
INPUT:
- ``gens`` -- a list of generators that coerce into ``self``
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] """
r""" 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 """
r""" 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 """
|