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
"Genus"
#***************************************************************************** # Copyright (C) 2007 David Kohel <kohel@maths.usyd.edu.au> # Gabriele Nebe <nebe@math.rwth-aachen.de> # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function
from sage.misc.all import prod from sage.arith.all import LCM from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import IntegerRing from sage.rings.rational_field import RationalField from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField import copy
def Genus(A): r""" Given a nonsingular symmetric matrix `A`, return the genus of `A`.
INPUT:
- `A` -- a symmetric matrix with coefficients in `\ZZ`
OUTPUT:
A ``GenusSymbol_global_ring`` object, encoding the Conway-Sloane genus symbol of the quadratic form whose Gram matrix is `A`.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import Genus sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: Genus(A) Genus of [1 1] [1 2] Genus symbol at 2: [1^2]_2 """
def LocalGenusSymbol(A,p): """ Given a nonsingular symmetric matrix A, return the local symbol of A at the prime p.
INPUT:
- A -- a symmetric matrix with coefficients in ZZ - p -- an integer prime p > 0
OUTPUT:
A Genus_Symbol_p_adic_ring object, encoding the Conway-Sloane genus symbol at p of the quadratic form whose Gram matrix is A.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: LocalGenusSymbol(A, 2) Genus symbol at 2: [1^2]_2 sage: LocalGenusSymbol(A, 3) Genus symbol at 3: 1^2
sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: LocalGenusSymbol(A, 2) Genus symbol at 2: [1^1 2^1]_2 sage: LocalGenusSymbol(A, 3) Genus symbol at 3: 1^-2 """
def is_GlobalGenus(G): """ Given a genus symbol G (specified by a collection of local symbols), return True in G represents the genus of a global quadratic form or lattice.
INPUT:
- G -- GenusSymbol_global_ring object
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring sage: from sage.quadratic_forms.genera.genus import Genus, is_GlobalGenus
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: G = Genus(A) sage: is_GlobalGenus(G) True
sage: from sage.quadratic_forms.genera.genus import Genus,is_GlobalGenus sage: G=Genus(matrix.diagonal([2,2,2,2])) sage: G._local_symbols[0]._symbol=[[0,2,3,0,0],[1,2,5,1,0]] sage: G._representative=None sage: is_GlobalGenus(G) False
""" # print "False in is_2_adic_genus(sym)" # print "False in (%s*%s).kronecker(%s)"%(a,b,p) return False else: if a.kronecker(p) != b: # print "False in %s.kronecker(%s) != *%s"%(a,p,b) return False oddity += loc.excess() # print "False in oddity" return False
def is_2_adic_genus(genus_symbol_quintuple_list): """ Given a 2-adic local symbol (as the underlying list of quintuples) check whether it is the 2-adic symbol of a 2-adic form.
INPUT:
- genus_symbol_quintuple_list -- a quintuple of integers (with certain restrictions).
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2) sage: is_2_adic_genus(G2.symbol_tuple_list()) True
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: G3 = LocalGenusSymbol(A, 3) sage: is_2_adic_genus(G3.symbol_tuple_list()) ## This raises an error Traceback (most recent call last): ... TypeError: The genus symbols are not quintuples, so it's not a genus symbol for the prime p=2.
sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: G2 = LocalGenusSymbol(A, 2) sage: is_2_adic_genus(G2.symbol_tuple_list()) True """ ## TO DO: Add explicit checking for the prime p here to ensure it's p=2... not just the quintuple checking below
## Check that we have a quintuple (i.e. that p=2 and not p >2)
## Check the Conway-Sloane conditions return False return False return False return False
def canonical_2_adic_compartments(genus_symbol_quintuple_list): """ Given a 2-adic local symbol (as the underlying list of quintuples) this returns a list of lists of indices of the genus_symbol_quintuple_list which are in the same compartment. A compartment is defined to be a maximal interval of Jordan components all (scaled) of type I (i.e. odd).
INPUT:
- genus_symbol_quintuple_list -- a quintuple of integers (with certain restrictions).
OUTPUT:
a list of lists of integers.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_compartments
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 2, 1, 1, 2]] sage: canonical_2_adic_compartments(G2.symbol_tuple_list()) [[0]]
sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]] sage: canonical_2_adic_compartments(G2.symbol_tuple_list()) [[0, 1]]
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: canonical_2_adic_compartments(G2.symbol_tuple_list()) [[0, 1, 2]]
sage: A = Matrix(ZZ, 2, 2, [2,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 2, 3, 0, 0]] sage: canonical_2_adic_compartments(G2.symbol_tuple_list()) ## No compartments here! []
NOTES:
See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples. """ else:
def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None): """ Given a 2-adic local symbol (as the underlying list of quintuples) this returns a list of lists of indices of the genus_symbol_quintuple_list which are in the same train. A train is defined to be a maximal interval of Jordan components so that at least one of each adjacent pair (allowing zero-dimensional Jordan components) is (scaled) of type I (i.e. odd). Note that an interval of length one respects this condition as there is no pair in this interval. In particular, every Jordan component is part of a train.
INPUT:
- ``genus_symbol_quintuple_list`` -- a quintuple of integers (with certain restrictions). - ``compartments`` -- this argument is deprecated
OUTPUT:
a list of lists of distinct integers.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_compartments sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_trains
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 2, 1, 1, 2]] sage: canonical_2_adic_trains(G2.symbol_tuple_list()) [[0]]
sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]] sage: canonical_2_adic_compartments(G2.symbol_tuple_list()) [[0, 1]]
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: canonical_2_adic_trains(G2.symbol_tuple_list()) [[0, 1, 2]]
sage: A = Matrix(ZZ, 2, 2, [2,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 2, 3, 0, 0]] sage: canonical_2_adic_trains(G2.symbol_tuple_list()) [[0]] sage: symbol = [[0, 1, 1, 1, 1],[1, 2, -1, 0, 0],[2, 1, 1, 1, 1],[3, 1, 1, 1, 1],[4, 1, 1, 1, 1],[5, 2, -1, 0, 0],[7, 1, 1, 1, 1],[10, 1, 1, 1, 1],[11, 1, 1, 1, 1],[12, 1, 1, 1, 1]] sage: canonical_2_adic_trains(symbol) [[0, 1, 2, 3, 4, 5], [6], [7, 8, 9]]
Check that :trac:`24818` is fixed::
sage: symbol = [[0, 1, 1, 1, 1],[1, 3, 1, 1, 1]] sage: canonical_2_adic_trains(symbol) [[0, 1]]
.. NOTE::
See [Co1999]_, pp. 381-382 for definitions and examples.
""" from sage.misc.superseded import deprecation deprecation(23955, "the compartments keyword has been deprecated")
# avoid a special case for the end of symbol # if a jordan component has rank zero it is considered even. # Hence, we have to remove the last entry of symbol at the end.
# start a new train if there are two adjacent even symbols else: # there is an odd jordan block adjacent to this jordan block # the train continues # the last train was never added. finally: #revert the input list to its original state
def canonical_2_adic_reduction(genus_symbol_quintuple_list): """ Given a 2-adic local symbol (as the underlying list of quintuples) this returns a canonical 2-adic symbol (again as a raw list of quintuples of integers) which has at most one minus sign per train and this sign appears on the smallest dimensional Jordan component in each train. This results from applying the "sign-walking" and "oddity fusion" equivalences.
INPUT:
- genus_symbol_quintuple_list -- a quintuple of integers (with certain restrictions). - compartments -- a list of lists of distinct integers (optional)
OUTPUT:
a list of lists of distinct integers.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_reduction
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 2, 1, 1, 2]] sage: canonical_2_adic_reduction(G2.symbol_tuple_list()) [[0, 2, 1, 1, 2]]
sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]] sage: canonical_2_adic_reduction(G2.symbol_tuple_list()) ## Oddity fusion occurred here! [[0, 1, 1, 1, 2], [1, 1, 1, 1, 0]]
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: canonical_2_adic_reduction(G2.symbol_tuple_list()) ## Oddity fusion occurred here! [[1, 2, -1, 1, 6], [2, 1, 1, 1, 0], [3, 1, 1, 1, 0]]
sage: A = Matrix(ZZ, 2, 2, [2,1,1,2]) sage: G2 = LocalGenusSymbol(A, 2); G2.symbol_tuple_list() [[0, 2, 3, 0, 0]] sage: canonical_2_adic_reduction(G2.symbol_tuple_list()) [[0, 2, -1, 0, 0]]
.. NOTE::
See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples.
.. TODO::
Add an example where sign walking occurs! """ # Protect the input from unwanted modification # Canonical determinants: else: # Oddity fusion: #print "End oddity fusion:", canonical_symbol # Sign walking: #print "End sign walking:", canonical_symbol
def basis_complement(B): """ Given an echelonized basis matrix (over a field), calculate a matrix whose rows form a basis complement (to the rows of B).
INPUT:
- B -- matrix over a field in row echelon form
OUTPUT:
a rectangular matrix over a field
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import basis_complement
sage: A = Matrix(ZZ, 2, 2, [1,1,1,1]) sage: B = A.kernel().echelonized_basis_matrix(); B [ 1 -1] sage: basis_complement(B) [0 1] """ else:
def signature_pair_of_matrix(A): """ Computes the signature pair (p, n) of a non-degenerate symmetric matrix, where
- p = number of positive eigenvalues of A - n = number of negative eigenvalues of A
INPUT:
- A -- symmetric matrix (assumed to be non-degenerate)
OUTPUT:
a pair (tuple) of integers.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import signature_pair_of_matrix
sage: A = Matrix(ZZ, 2, 2, [-1,0,0,3]) sage: signature_pair_of_matrix(A) (1, 1)
sage: A = Matrix(ZZ, 2, 2, [-1,1,1,7]) sage: signature_pair_of_matrix(A) (1, 1)
sage: A = Matrix(ZZ, 2, 2, [3,1,1,7]) sage: signature_pair_of_matrix(A) (2, 0)
sage: A = Matrix(ZZ, 2, 2, [-3,1,1,-11]) sage: signature_pair_of_matrix(A) (0, 2)
sage: A = Matrix(ZZ, 2, 2, [1,1,1,1]) sage: signature_pair_of_matrix(A) Traceback (most recent call last): ... ArithmeticError: given matrix is not invertible """
# Check that the matrix is non-degenerate (i.e. no zero eigenvalues)
# Return the pair (p,n)
def p_adic_symbol(A, p, val): """ Given a symmetric matrix A and prime p, return the genus symbol at p.
val = valuation of the maximal elementary divisor of A needed to obtain enough precision calculation is modulo p to the val+3
.. TODO::
Some description of the definition of the genus symbol.
INPUT:
- A -- symmetric matrix with integer coefficients - p -- prime number > 0 - val -- integer >= 0
OUTPUT:
a list of lists of integers
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p_adic_symbol(A, 2, 2) [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
sage: p_adic_symbol(A, 3, 1) [[0, 3, 1], [1, 1, -1]]
""" else: # Construct the blocks for the Jordan decomposition [F,X;X,A_new] # X = C*A*B.transpose() # A = B*A*B.transpose() - X.transpose()*U*X
def is_even_matrix(A): """ Determines if the integral symmetric matrix A is even (i.e. represents only even numbers). If not, then it returns the index of an odd diagonal entry. If it is even, then we return the index -1.
INPUT:
- A -- symmetric integer matrix
OUTPUT:
a pair of the form (boolean, integer)
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import is_even_matrix
sage: A = Matrix(ZZ, 2, 2, [1,1,1,1]) sage: is_even_matrix(A) (False, 0)
sage: A = Matrix(ZZ, 2, 2, [2,1,1,2]) sage: is_even_matrix(A) (True, -1) """
def split_odd(A): """ Given a non-degenerate Gram matrix A (mod 8), return a splitting [u] + B such that u is odd and B is not even.
INPUT:
- A -- an odd symmetric matrix with integer coefficients (which admits a splitting as above).
OUTPUT:
a pair (u, B) consisting of an odd integer u and an odd integral symmetric matrix B.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import is_even_matrix sage: from sage.quadratic_forms.genera.genus import split_odd
sage: A = Matrix(ZZ, 2, 2, [1,2,2,3]) sage: is_even_matrix(A) (False, 0) sage: split_odd(A) (1, [-1])
sage: A = Matrix(ZZ, 2, 2, [1,2,2,5]) sage: split_odd(A) (1, [1])
sage: A = Matrix(ZZ, 2, 2, [1,1,1,1]) sage: is_even_matrix(A) (False, 0) sage: split_odd(A) ## This fails because no such splitting exists. =( Traceback (most recent call last): ... RuntimeError: The matrix A does not admit a non-even splitting.
sage: A = Matrix(ZZ, 2, 2, [1,2,2,6]) sage: split_odd(A) ## This fails because no such splitting exists. =( Traceback (most recent call last): ... RuntimeError: The matrix A does not admit a non-even splitting.
""" C[j,j] = 1 C[j,i] = -A[j,i]*u else: # TODO: we could manually (re)construct the kernel here... else: I[0,i] = 1 - A[0,i]*u i = 0 else: C[j,j+1] = 1 C[j,i] = -A[j+1,i]*u
def trace_diag_mod_8(A): """ Return the trace of the diagonalised form of A of an integral symmetric matrix which is diagonalizable mod 8. (Note that since the Jordan decomposition into blocks of size <= 2 is not unique here, this is not the same as saying that A is always diagonal in any 2-adic Jordan decomposition!)
INPUT:
- A -- symmetric matrix with coefficients in Z which is odd in Z/2Z and has determinant not divisible by 8.
OUTPUT:
an integer
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import is_even_matrix sage: from sage.quadratic_forms.genera.genus import split_odd sage: from sage.quadratic_forms.genera.genus import trace_diag_mod_8
sage: A = Matrix(ZZ, 2, 2, [1,2,2,3]) sage: is_even_matrix(A) (False, 0) sage: split_odd(A) (1, [-1]) sage: trace_diag_mod_8(A) 0
sage: A = Matrix(ZZ, 2, 2, [1,2,2,5]) sage: split_odd(A) (1, [1]) sage: trace_diag_mod_8(A) 2 """
def two_adic_symbol(A, val): """ Given a symmetric matrix A and prime p, return the genus symbol at p.
val = valuation of maximal 2-elementary divisor
The genus symbol of a component 2^m*f is of the form (m,n,s,d[,o]), where
- m = valuation of the component - n = dimension of f - d = det(f) in {1,3,5,7} - s = 0 (or 1) if even (or odd) - o = oddity of f (= 0 if s = 0) in Z/8Z
INPUT:
- A -- symmetric matrix with integer coefficients - val -- integer >=0
OUTPUT:
a list of lists of integers (representing a Conway-Sloane 2-adic symbol)
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import two_adic_symbol
sage: A = diagonal_matrix(ZZ, [1,2,3,4]) sage: two_adic_symbol(A, 2) [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]
"""
## Deal with the matrix being non-degenerate mod 2. # d0 = ZZ(A_8.determinant()) # no determinant over Z/8Z print("A:") print(A) assert False else:
## Deal with the matrix being degenerate mod 2. else: # compute oddity modulo 8: # d0 = A_8.det() # no determinant over Z/8Z print("A:") print(A_new) assert False else:
class Genus_Symbol_p_adic_ring(object): """ Local genus symbol over a p-adic ring. """ def __init__(self, prime, symbol, check = True): """ Create the local genus symbol of given prime and local invariants.
The genus symbol of a component p^m*A for odd prime = p is of the form (m,n,d), where
- m = valuation of the component - n = rank of A - d = det(A) in {1,u} for normalized quadratic non-residue u.
The genus symbol of a component 2^m*A is of the form (m,n,s,d,o), where
- m = valuation of the component - n = rank of A - d = det(A) in {1,3,5,7} - s = 0 (or 1) if even (or odd) - o = oddity of A (= 0 if s = 0) in Z/8Z = the trace of the diagonalization of A
The genus symbol is a list of such symbols (ordered by m) for each of the Jordan blocks A_1,...,A_t.
Reference: Conway and Sloane 3rd edition, Chapter 15, Section 7.
WARNING/NOTE: This normalization seems non-standard, and we should review this entire class to make sure that we have our doubling conventions straight throughout! This is especially noticeable in the determinant and excess methods!!
INPUT:
- prime -- a prime integer > 0 - symbol -- the list of invariants for Jordan blocks A_t,...,A_t given as a list of lists of integers
OUTPUT:
None
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = diagonal_matrix(ZZ, [1,2,3,4]) sage: p = 2 sage: s2 = p_adic_symbol(A, p, 2); s2 [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]] sage: G = Genus_Symbol_p_adic_ring(p,s2);G Genus symbol at 2: [1^-2 2^1 4^1]_6 sage: G == loads(dumps(G)) True
sage: A = diagonal_matrix(ZZ, [1,2,3,4]) sage: p = 3 sage: s3 = p_adic_symbol(A, p, 1); s3 [[0, 3, -1], [1, 1, 1]] sage: G = Genus_Symbol_p_adic_ring(p,s3);G Genus symbol at 3: 1^-3 3^1 sage: G == loads(dumps(G)) True
"""
def __repr__(self): r""" String representation for the p-adic genus symbol
INPUT:
None
OUTPUT:
a string
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring sage: symbol = [[0, 4, -1, 0, 0],[1, 2, 1, 1, 2],[2, 1, 1, 1, 1],[4, 4, 1, 0, 0],[5, 1, 1, 1, 1]] sage: g = Genus_Symbol_p_adic_ring(2,symbol) sage: g._canonical_symbol = [[0, 4, 1, 0, 0],[1, 2, 1, 1, 3],[2, 1, 1, 1, 0],[4, 4, 1, 0, 0],[5, 1, 1, 1, 1]] sage: g Genus symbol at 2: 1^4 [2^2 4^1]_1 :16^4 [32^1]_1
""" #mark the beginning of a train with a colon #collect the indices where compartments begin and end
#mark the beginning of this compartment with [ #close this compartment with ] and remove a space #the oddity belongs to the compartment #remove the first colon
else:
def _latex_(self): """ The LaTeX representation of this local genus symbol.
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring sage: symbol = [[0, 4, -1, 0, 0],[1, 2, 1, 1, 2],[2, 1, 1, 1, 1],[4, 4, 1, 0, 0],[5, 1, 1, 1, 1]] sage: g = Genus_Symbol_p_adic_ring(2,symbol) sage: g._canonical_symbol = [[0, 4, 1, 0, 0],[1, 2, 1, 1, 3],[2, 1, 1, 1, 0],[4, 4, 1, 0, 0],[5, 1, 1, 1, 1]] sage: g._latex_() '\\mbox{Genus symbol at } 2\\mbox{: }1^{4} [2^{2} 4^{1}]_{1} :16^{4} [32^{1}]_{1}'
""" #mark the beginning of a train with a colon #collect the indices where compartments begin and end
#mark the beginning of this compartment with [ #close this compartment with ] and remove a space #the oddity belongs to the compartment #remove the first colon
else: for s in self._symbol: CS_string += " {%s}^{%s}" % (p**s[0], s[2]*s[1])
def __eq__(self, other): """ Determines if two genus symbols are equal (not just equivalent!).
INPUT:
a Genus_Symbol_p_adic_ring object
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = diagonal_matrix(ZZ, [1,2,3,4]) sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)) sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 1))
sage: G2 == G3 False sage: G3 == G2 False sage: G2 == G2 True sage: G3 == G3 True
"""
def __ne__(self, other): """ Determines if two genus symbols are unequal (not just inequivalent!).
INPUT:
a ``Genus_Symbol_p_adic_ring`` object
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = diagonal_matrix(ZZ, [1,2,3,4]) sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)) sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 1))
sage: G2 != G3 True sage: G3 != G2 True sage: G2 != G2 False sage: G3 != G3 False
"""
## Added these two methods to make this class iterable... #def __getitem__(self, i): # return self._symbol[i] # #def len(self): # return len(self._symbol) ## ------------------------------------------------------
def canonical_symbol(self): """ Return (and cache) the canonical p-adic genus symbol. This is only really affects the 2-adic symbol, since when p > 2 the symbol is already canonical.
INPUT:
None
OUTPUT:
a list of lists of integers
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = Matrix(ZZ, 2, 2, [1,1,1,2]) sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() [[0, 2, 1, 1, 2]] sage: G2.canonical_symbol() [[0, 2, 1, 1, 2]]
sage: A = Matrix(ZZ, 2, 2, [1,0,0,2]) sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]] sage: G2.canonical_symbol() ## Oddity fusion occurred here! [[0, 1, 1, 1, 2], [1, 1, 1, 1, 0]]
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: G2.canonical_symbol() ## Oddity fusion occurred here! [[1, 2, -1, 1, 6], [2, 1, 1, 1, 0], [3, 1, 1, 1, 0]]
sage: A = Matrix(ZZ, 2, 2, [2,1,1,2]) sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() [[0, 2, 3, 0, 0]] sage: G2.canonical_symbol() [[0, 2, -1, 0, 0]]
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3.symbol_tuple_list() [[0, 3, 1], [1, 1, -1]] sage: G3.canonical_symbol() [[0, 3, 1], [1, 1, -1]]
.. NOTE::
See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples.
.. TODO::
Add an example where sign walking occurs! """ else:
def symbol_tuple_list(self): """ Returns the underlying list of lists of integers defining the genus symbol.
INPUT:
None
OUTPUT:
list of lists of integers
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3 Genus symbol at 3: 1^3 3^-1 sage: G3.symbol_tuple_list() [[0, 3, 1], [1, 1, -1]] sage: type(G3.symbol_tuple_list()) <... 'list'>
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2 Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: type(G2.symbol_tuple_list()) <... 'list'>
"""
def number_of_blocks(self): """ Returns the number of positive dimensional symbols/Jordan blocks
INPUT:
None
OUTPUT:
integer >= 0
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2.symbol_tuple_list() [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]] sage: G2.number_of_blocks() 3
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3.symbol_tuple_list() [[0, 3, 1], [1, 1, -1]] sage: G3.number_of_blocks() 2
"""
def determinant(self): """ Returns the (p-part of the) determinant (square-class) of the Hessian matrix of the quadratic form (given by regarding the integral symmetric matrix which generated this genus symbol as the Gram matrix of Q) associated to this local genus symbol.
INPUT:
None
OUTPUT:
an integer
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2 Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: G2.determinant() 128
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3 Genus symbol at 3: 1^3 3^-1 sage: G3.determinant() 3 """
def rank(self): """ Returns the dimension of a quadratic form associated to this genus symbol.
.. TODO::
DELETE THIS METHOD IN FAVOR OF THE dimension() METHOD BELOW!
INPUT:
None
OUTPUT:
an integer >= 0
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2 Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: G2.rank() 4
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3 Genus symbol at 3: 1^3 3^-1 sage: G3.rank() 4
"""
def dimension(self): """ Returns the dimension of a quadratic form associated to this genus symbol.
INPUT:
None
OUTPUT:
an integer >= 0
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2 Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: G2.dimension() 4
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 3 sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3 Genus symbol at 3: 1^3 3^-1 sage: G3.dimension() 4
"""
def excess(self): """ Returns the p-excess of the quadratic form whose Hessian matrix is the symmetric matrix A. When p = 2 the p-excess is called the oddity.
WARNING/NOTE: This normalization seems non-standard, and we should review this entire class to make sure that we have our doubling conventions straight throughout!
REFERENCE:
Conway and Sloane Book, 3rd edition, pp 370-371.
INPUT:
None
OUTPUT:
an integer
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: AC = diagonal_matrix(ZZ, [1,3,-3]) sage: p=2; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 1 sage: p=3; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0 sage: p=5; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0 sage: p=7; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0 sage: p=11; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0
sage: AC = 2 * diagonal_matrix(ZZ, [1,3,-3]) sage: p=2; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 1 sage: p=3; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0 sage: p=5; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0 sage: p=7; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0 sage: p=11; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess() 0
sage: A = 2*diagonal_matrix(ZZ, [1,2,3,4]) sage: p=2; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess() 2 sage: p=3; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess() 6 sage: p=5; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess() 0 sage: p=7; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess() 0 sage: p=11; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess() 0
""" else:
def trains(self): """ Compute the indices for each of the trains in this local genus symbol if it is associated to the prime p=2 (and raise an error for all other primes).
INPUT:
None
OUTPUT:
a list of integers >= 0
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2 Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: G2.trains() [[0, 1, 2]]
""" ## Check that p = 2 raise TypeError("trains() only makes sense when the prime of the p_adic_Genus_Symbol is p=2")
def compartments(self): """ Compute the indices for each of the compartments in this local genus symbol if it is associated to the prime p=2 (and raise an error for all other primes).
INPUT:
None
OUTPUT:
a list of integers >= 0
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import p_adic_symbol sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: p = 2 sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2 Genus symbol at 2: [2^-2 4^1 8^1]_6 sage: G2.compartments() [[0, 1, 2]]
""" ## Check that p = 2 raise TypeError("compartments() only makes sense when the prime of the p_adic_Genus_Symbol is p=2")
class GenusSymbol_global_ring(object): """ This represents a collection of local genus symbols (at primes) and signature information which represent the genus of a non-degenerate integral lattice. """
def __init__(self, A, max_elem_divisors=None): """ Initialize a global genus symbol from a non-degenerate integral gram matrix (and possibly information about its largest elementary divisors).
INPUT:
- A -- a symmetric matrix with integer coefficients - max_elem_divisors -- the input precision for valuation of maximal p-elementary divisor. (OPTIONAL)
OUTPUT:
None
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: G = GenusSymbol_global_ring(A);G Genus of [2 0 0 0] [0 4 0 0] [0 0 6 0] [0 0 0 8] Genus symbol at 2: [2^-2 4^1 8^1]_6 Genus symbol at 3: 1^3 3^-1 sage: G == loads(dumps(G)) True
"""
def __repr__(self): r""" Returns a string representing the global genus symbol.
INPUT:
None
OUTPUT:
a string
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: GS = GenusSymbol_global_ring(A) sage: GS Genus of [2 0 0 0] [0 4 0 0] [0 0 6 0] [0 0 0 8] Genus symbol at 2: [2^-2 4^1 8^1]_6 Genus symbol at 3: 1^3 3^-1
sage: A2 = Matrix(ZZ,2,2,[2,-1,-1,2]) sage: GenusSymbol_global_ring(A2) Genus of [ 2 -1] [-1 2] Genus symbol at 2: 1^-2 Genus symbol at 3: 1^-1 3^-1
"""
def _latex_(self): """ The Latex representation of this lattice.
EXAMPLES::
sage: D4=QuadraticForm(Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2])) sage: G=D4.global_genus_symbol() sage: G._latex_() '\\mbox{Genus of}\\\\\\left(\\begin{array}{rrrr}\n2 & 0 & 0 & -1 \\\\\n0 & 2 & 0 & -1 \\\\\n0 & 0 & 2 & -1 \\\\\n-1 & -1 & -1 & 2\n\\end{array}\\right)\\\\\\\\\\mbox{Genus symbol at } 2\\mbox{: }1^{-2} :2^{-2} ' """
def __eq__(self, other): """ Determines if two global genus symbols are equal (not just equivalent!).
INPUT:
a ``GenusSymbol_global_ring`` object
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
sage: A1 = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: GS1 = GenusSymbol_global_ring(A1) sage: A2 = DiagonalQuadraticForm(ZZ, [1,2,3,5]).Hessian_matrix() sage: GS2 = GenusSymbol_global_ring(A2)
sage: GS1 == GS2 False
sage: GS2 == GS1 False
sage: GS1 == GS1 True
sage: GS2 == GS2 True
TESTS::
sage: D4=QuadraticForm(Matrix(ZZ,4,4,[2,0,0,-1,0,2,0,-1,0,0,2,-1,-1,-1,-1,2])) sage: G=D4.global_genus_symbol() sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) True sage: G==deepcopy(G) True sage: sage.quadratic_forms.genera.genus.is_GlobalGenus(G) True """ return False
def __ne__(self, other): """ Determines if two global genus symbols are unequal (not just inequivalent!).
INPUT:
a ``GenusSymbol_global_ring`` object
OUTPUT:
boolean
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
sage: A1 = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix() sage: GS1 = GenusSymbol_global_ring(A1) sage: A2 = DiagonalQuadraticForm(ZZ, [1,2,3,5]).Hessian_matrix() sage: GS2 = GenusSymbol_global_ring(A2)
sage: GS1 != GS2 True
sage: GS2 != GS1 True
sage: GS1 != GS1 False
sage: GS2 != GS2 False
"""
def signature_pair_of_matrix(self): """ Returns the signature pair (p, n) of the (non-degenerate) global genus symbol, where p is the number of positive eigenvalues and n is the number of negative eigenvalues.
INPUT:
None
OUTPUT:
a pair of integers (p, n) each >= 0
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,-2,3,4,8,-11]).Hessian_matrix() sage: GS = GenusSymbol_global_ring(A) sage: GS.signature_pair_of_matrix() (4, 2)
"""
def determinant(self): """ Returns the determinant of this genus, where the determinant is the Hessian determinant of the quadratic form whose Gram matrix is the Gram matrix giving rise to this global genus symbol.
INPUT:
None
OUTPUT:
an integer
EXAMPLES::
sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
sage: A = DiagonalQuadraticForm(ZZ, [1,-2,3,4]).Hessian_matrix() sage: GS = GenusSymbol_global_ring(A) sage: GS.determinant() -384
""" |