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
""" Tornaria Methods for Computing with Quadratic Forms """
#***************************************************************************** # Copyright (C) 2007 Gonzalo Tornaria # # 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/ #***************************************************************************** from six.moves import range
from sage.rings.integer_ring import ZZ from sage.misc.functional import is_odd
from sage.libs.pari.all import pari from sage.misc.all import prod from sage.arith.all import (factor, gcd, prime_to_m_part, CRT_vectors, hilbert_symbol, kronecker_symbol)
from sage.quadratic_forms.quadratic_form import QuadraticForm__constructor as QuadraticForm from sage.modules.free_module import FreeModule from sage.modules.free_module_element import vector
## TO DO -- Add second argument # def __call__(self,v,w=None): # if w is None: # return half(v * self._matrix_() * v) # else: # return v * self._matrix_() * w
def disc(self): r""" Return the discriminant of the quadratic form, defined as
- `(-1)^n {\rm det}(B)` for even dimension `2n` - `{\rm det}(B)/2` for odd dimension
where `2Q(x) = x^t B x`.
This agrees with the usual discriminant for binary and ternary quadratic forms.
EXAMPLES::
sage: DiagonalQuadraticForm(ZZ, [1]).disc() 1 sage: DiagonalQuadraticForm(ZZ, [1,1]).disc() -4 sage: DiagonalQuadraticForm(ZZ, [1,1,1]).disc() 4 sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).disc() 16
""" else:
def content(self): """ Return the GCD of the coefficients of the quadratic form.
.. warning::
Only works over Euclidean domains (probably just `\ZZ`).
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1]) sage: Q.matrix().gcd() 2 sage: Q.content() 1 sage: DiagonalQuadraticForm(ZZ, [1, 1]).is_primitive() True sage: DiagonalQuadraticForm(ZZ, [2, 4]).is_primitive() False sage: DiagonalQuadraticForm(ZZ, [2, 4]).primitive() Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 0 ] [ * 2 ] """
## in quadratic_form.py #def is_primitive(self): # """ # Checks if the form is a multiple of another form... only over ZZ for now. # """ # return self.content() == 1
## in quadratic_form.py #def primitive(self): # """ # Return a primitive quadratic forms in the similarity class of the given form. # # This only works when we have GCDs... so over ZZ. # """ # c=self.content() # new_coeffs = [self.base_ring()(a/c) for a in self.__coeffs] # return QuadraticForm(self.base_ring(), self.dim(), new_coeffs)
def adjoint(self): """ This gives the adjoint (integral) quadratic form associated to the given form, essentially defined by taking the adjoint of the matrix.
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 2, [1,2,5]) sage: Q.adjoint() Quadratic form in 2 variables over Integer Ring with coefficients: [ 5 -2 ] [ * 1 ]
::
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 39 2 8 ] [ * 19 4 ] [ * * 8 ]
""" else:
def antiadjoint(self): """ This gives an (integral) form such that its adjoint is the given form.
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint().antiadjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 -1 ] [ * 2 -1 ] [ * * 5 ] sage: Q.antiadjoint() Traceback (most recent call last): ... ValueError: not an adjoint
""" else: return self.adjoint().scale_by_factor( R(1) / d**(n-2) )
def is_adjoint(self): """ Determines if the given form is the adjoint of another form
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.is_adjoint() False sage: Q.adjoint().is_adjoint() True
"""
def reciprocal(self): """ This gives the reciprocal quadratic form associated to the given form. This is defined as the multiple of the primitive adjoint with the same content as the given form.
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.reciprocal() Quadratic form in 3 variables over Integer Ring with coefficients: [ 37 0 0 ] [ * 37 0 ] [ * * 1 ] sage: Q.reciprocal().reciprocal() Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 0 ] [ * 1 0 ] [ * * 37 ] sage: Q.reciprocal().reciprocal() == Q True
"""
def omega(self): """ This is the content of the adjoint of the primitive associated quadratic form.
Ref: See Dickson's "Studies in Number Theory".
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.omega() 4
"""
def delta(self): """ This is the omega of the adjoint form, which is the same as the omega of the reciprocal form.
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.delta() 148
"""
def level__Tornaria(self): """ Return the level of the quadratic form, defined as
level(B) for even dimension level(B)/4 for odd dimension
where 2Q(`x`) `= x^t * B * x`.
This agrees with the usual level for even dimension...
EXAMPLES::
sage: DiagonalQuadraticForm(ZZ, [1]).level__Tornaria() 1 sage: DiagonalQuadraticForm(ZZ, [1,1]).level__Tornaria() 4 sage: DiagonalQuadraticForm(ZZ, [1,1,1]).level__Tornaria() 1 sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).level__Tornaria() 4
"""
def discrec(self): """ Return the discriminant of the reciprocal form.
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1,1,37]) sage: Q.disc() 148 sage: Q.discrec() 5476 sage: [4 * 37, 4 * 37^2] [148, 5476]
"""
### Rational equivalence
def hasse_conductor(self): """ This is the product of all primes where the Hasse invariant equals -1
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.hasse_invariant(2) -1 sage: Q.hasse_invariant(37) -1 sage: Q.hasse_conductor() 74
::
sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).hasse_conductor() 1 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() 10 """
def clifford_invariant(self, p): """ This is the Clifford invariant, i.e. the class in the Brauer group of the Clifford algebra for even dimension, of the even Clifford Algebra for odd dimension.
See Lam (AMS GSM 67) p. 117 for the definition, and p. 119 for the formula relating it to the Hasse invariant.
EXAMPLES:
For hyperbolic spaces, the clifford invariant is +1::
sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_invariant(2) 1 sage: (H + H).clifford_invariant(2) 1 sage: (H + H + H).clifford_invariant(2) 1 sage: (H + H + H + H).clifford_invariant(2) 1
"""
def clifford_conductor(self): """ This is the product of all primes where the Clifford invariant is -1
Note: For ternary forms, this is the discriminant of the quaternion algebra associated to the quadratic space (i.e. the even Clifford algebra)
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.clifford_invariant(2) 1 sage: Q.clifford_invariant(37) -1 sage: Q.clifford_conductor() 37
::
sage: DiagonalQuadraticForm(ZZ, [1, 1, 1]).clifford_conductor() 2 sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).clifford_conductor() 30
For hyperbolic spaces, the clifford conductor is 1::
sage: H = QuadraticForm(ZZ, 2, [0, 1, 0]) sage: H.clifford_conductor() 1 sage: (H + H).clifford_conductor() 1 sage: (H + H + H).clifford_conductor() 1 sage: (H + H + H + H).clifford_conductor() 1
"""
### Genus theory
def basiclemma(self,M): """ Finds a number represented by self and coprime to M.
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 2, [2, 1, 3]) sage: Q.basiclemma(6) 71
"""
def basiclemmavec(self,M): """ Finds a vector where the value of the quadratic form is coprime to M.
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 2, [2, 1, 5]) sage: Q.basiclemmavec(10) (6, 5) sage: Q(_) 227
""" return V(0)
for i in range(self.dim()): for j in range(i): M1 = prime_to_m_part(M0, self[i,j]) if M1 != 1: vec.append(V.i + V.j) mod.append(M1) M0 = M0/M1 if M0 == 1: return __crt_list(vec,mod)
raise ValueError("not primitive form")
### FIXME: get the rules for validity of characters straight... ### p=2 might be bad!!! def xi(self,p): """ Return the value of the genus characters Xi_p... which may be missing one character. We allow -1 as a prime.
Reference: Dickson's "Studies in the Theory of Numbers"
EXAMPLES::
sage: Q1 = QuadraticForm(ZZ, 3, [1, 1, 1, 14, 3, 14]) sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) sage: [Q1.omega(), Q2.omega()] [5, 5] sage: [Q1.hasse_invariant(5), Q2.hasse_invariant(5)] # equivalent over Q_5 [1, 1] sage: [Q1.xi(5), Q2.xi(5)] # not equivalent over Z_5 [1, -1]
""" raise ValueError("not a valid character") raise ValueError("not a valid character")
def xi_rec(self,p): """ Return Xi(`p`) for the reciprocal form.
EXAMPLES::
sage: Q1 = QuadraticForm(ZZ, 3, [1, 1, 1, 14, 3, 14]) sage: Q2 = QuadraticForm(ZZ, 3, [2, -1, 0, 2, 0, 50]) sage: [Q1.clifford_conductor(), Q2.clifford_conductor()] # equivalent over Q [3, 3] sage: Q1.is_locally_equivalent_to(Q2) # not in the same genus False sage: [Q1.delta(), Q2.delta()] [480, 480] sage: factor(480) 2^5 * 3 * 5 sage: list(map(Q1.xi_rec, [-1,2,3,5])) [-1, -1, -1, 1] sage: list(map(Q2.xi_rec, [-1,2,3,5])) [-1, -1, -1, -1]
"""
def lll(self): """ Return an LLL-reduced form of Q (using Pari).
EXAMPLES::
sage: Q = QuadraticForm(ZZ, 4, range(1,11)) sage: Q.is_definite() True sage: Q.lll() Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 1 0 ] [ * 4 3 3 ] [ * * 6 3 ] [ * * * 6 ]
"""
def representation_number_list(self, B): """ Return the vector of representation numbers < B.
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1,1,1,1,1]) sage: Q.representation_number_list(10) [1, 16, 112, 448, 1136, 2016, 3136, 5504, 9328, 12112] """
def representation_vector_list(self, B, maxvectors=10**8): """ Find all vectors `v` where `Q(v) < B`.
This only works for positive definite quadratic forms.
EXAMPLES::
sage: Q = DiagonalQuadraticForm(ZZ, [1, 1]) sage: Q.representation_vector_list(10) [[(0, 0)], [(0, 1), (0, -1), (1, 0), (-1, 0)], [(1, 1), (-1, -1), (1, -1), (-1, 1)], [], [(0, 2), (0, -2), (2, 0), (-2, 0)], [(1, 2), (-1, -2), (1, -2), (-1, 2), (2, 1), (-2, -1), (2, -1), (-2, 1)], [], [], [(2, 2), (-2, -2), (2, -2), (-2, 2)], [(0, 3), (0, -3), (3, 0), (-3, 0)]] sage: list(map(len, _)) [1, 4, 4, 0, 4, 8, 0, 0, 4, 4] sage: Q.representation_number_list(10) [1, 4, 4, 0, 4, 8, 0, 0, 4, 4]
TESTS::
sage: R = QuadraticForm(ZZ,2,[-4,-3,0]) sage: R.representation_vector_list(10) Traceback (most recent call last): ... PariError: domain error in minim0: form is not positive definite """
raise RuntimeError("insufficient number of vectors")
### zeros
def is_zero(self, v, p=0): """ Determines if the vector v is on the conic Q(x) = 0 (mod p).
EXAMPLES::
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q1.is_zero([0,1,0], 2) True sage: Q1.is_zero([1,1,1], 2) True sage: Q1.is_zero([1,1,0], 2) False
"""
def is_zero_nonsingular(self, v, p=0): """ Determines if the vector `v` is on the conic Q(`x`) = 0 (mod `p`), and that this point is non-singular point of the conic.
EXAMPLES::
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q1.is_zero_nonsingular([1,1,1], 2) True sage: Q1.is_zero([1, 19, 2], 37) True sage: Q1.is_zero_nonsingular([1, 19, 2], 37) False
""" return False
def is_zero_singular(self, v, p=0): """ Determines if the vector `v` is on the conic Q(`x`) = 0 (mod `p`), and that this point is singular point of the conic.
EXAMPLES::
sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q1.is_zero([1,1,1], 2) True sage: Q1.is_zero_singular([1,1,1], 2) False sage: Q1.is_zero_singular([1, 19, 2], 37) True
""" return False
|