Ticket #5954: patch-1__QF_genus_symbols__3.4.1.patch

File patch-1__QF_genus_symbols__3.4.1.patch, 57.3 KB (added by jonhanke, 10 years ago)
  • sage/quadratic_forms/all.py

    # HG changeset patch
    # User Jonathan Hanke <jonhanke@gmail.com>
    # Date 1241156664 25200
    # Node ID af0f19cc490e35ac3b250e6365ad6d504f7d71e2
    # Parent  891da50821bd920d08245dfb718a0f99bda908cc
    Added documentation/doctests for all quadratic form genus symbol routines.
    
    Also:
        - Replaced the signature routine in genera/genus.py
        - (Re)wrote the signature_vector and rational_diagonal_form
          routines in quadratic_form.local_field_invariants.py
        - Changed the signature routine in genera/genus.py to give exact
          answers when working over the rationals by using the
          rational_diagonal_form in the QuadraticForm class.
    
    diff -r 891da50821bd -r af0f19cc490e sage/quadratic_forms/all.py
    a b  
    99from special_values import gamma__exact, zeta__exact, QuadraticBernoulliNumber, \
    1010      quadratic_L_function__exact, quadratic_L_function__numerical
    1111
    12 from genera.genus import is_GlobalGenus, is_2_adic_genus, is_trivial_symbol
     12from genera.genus import is_GlobalGenus, is_2_adic_genus
     13#is_trivial_symbol
    1314
    1415from constructions import BezoutianQuadraticForm, HyperbolicPlane_quadratic_form
    1516
  • sage/quadratic_forms/genera/genus.py

    diff -r 891da50821bd -r af0f19cc490e sage/quadratic_forms/genera/genus.py
    a b  
    1616from sage.rings.rational_field import RationalField
    1717from sage.rings.integer import Integer
    1818
     19
    1920def Genus(A):
    2021    """
    2122    Given a nonsingular symmetric matrix A, return the genus of A.
    2223
    23     TODO: Implement some datastructure for quadratic forms and lattices.
     24    INPUT:
     25        A -- a symmetric matrix with coefficients in ZZ
     26
     27    OUTPUT:
     28        A GenusSymbol_global_ring object, encoding the Conway-Sloane
     29        genus symbol of the quadratic form whose Gram matrix is A.
     30
     31    EXAMPLES:
     32        sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     33        sage: from sage.quadratic_forms.genera.genus import Genus
     34
     35        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     36        sage: Genus(A)
     37        Genus of [1 1]
     38        [1 2]
    2439    """
    2540    return GenusSymbol_global_ring(A)
    2641
     42
     43
    2744def LocalGenusSymbol(A,p):
    2845    """
    29     Given a nonsingular symmetric matrix A, return the local symbol of A.
     46    Given a nonsingular symmetric matrix A, return the local symbol of A at the prime p.
     47
     48    INPUT:
     49        A -- a symmetric matrix with coefficients in ZZ
     50        p -- an integer prime p > 0
     51
     52    OUTPUT:
     53        A Genus_Symbol_p_adic_ring object, encoding the Conway-Sloane
     54        genus symbol at p of the quadratic form whose Gram matrix is A.
     55
     56    EXAMPLES:
     57        sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
     58
     59        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     60        sage: LocalGenusSymbol(A, 2)
     61        Genus symbol at 2 : [[0, 2, 1, 1, 2]]
     62        sage: LocalGenusSymbol(A, 3)
     63        Genus symbol at 3 : [[0, 2, 1]]
     64
     65        sage: A = Matrix(ZZ, 2, 2, [1,0,0,2])
     66        sage: LocalGenusSymbol(A, 2)
     67        Genus symbol at 2 : [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     68        sage: LocalGenusSymbol(A, 3)
     69        Genus symbol at 3 : [[0, 2, -1]]
    3070    """
    3171    val = A.determinant().valuation(p)
    3272    symbol = p_adic_symbol(A, p, val = val)
    3373    return Genus_Symbol_p_adic_ring(p, symbol)
    3474
     75
     76
    3577def is_GlobalGenus(G):
    3678    """
    3779    Given a genus symbol G (specified by a collection of local symbols), return
    3880    True in G represents the genus of a global quadratic form or lattice.
     81
     82    INPUT:
     83        G -- GenusSymbol_global_ring object
     84
     85    OUTPUT:
     86        boolean
     87
     88    EXAMPLES:
     89        sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     90        sage: from sage.quadratic_forms.genera.genus import Genus, is_GlobalGenus
     91
     92        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     93        sage: G = Genus(A)
     94        sage: is_GlobalGenus(G)
     95        True
    3996    """
    4097    D = G.determinant()
    41     r, s = G.signature_of_matrix()
     98    r, s = G.signature_pair_of_matrix()
    4299    oddity = r - s
    43100    for loc in G._local_symbols:
    44101        p = loc._prime
     
    64121        return False
    65122    return True
    66123   
    67 def is_2_adic_genus(symbol):
     124
     125
     126def is_2_adic_genus(genus_symbol_quintuple_list):
    68127    """
    69     Given a 2-adic local symbols check whether it is the 2-adic symbol
    70     of a 2-adic form.
     128    Given a 2-adic local symbol (as the underlying list of quintuples)
     129    check whether it is the 2-adic symbol of a 2-adic form.
     130
     131    INPUT:
     132        genus_symbol_quintuple_list -- a quintuple of integers (with certain
     133        rectrictions).
     134
     135    OUTPUT:
     136        boolean
     137
     138    EXAMPLES:
     139        sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
     140
     141        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     142        sage: G2 = LocalGenusSymbol(A, 2)
     143        sage: is_2_adic_genus(G2.symbol_tuple_list())
     144        True
     145
     146        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     147        sage: G3 = LocalGenusSymbol(A, 3)
     148        sage: is_2_adic_genus(G3.symbol_tuple_list())  ## This raises an error
     149        Traceback (most recent call last):
     150        ...
     151        TypeError: The genus symbols are not quintuples, so it's not a genus symbol for the prime p=2.
     152
     153        sage: A = Matrix(ZZ, 2, 2, [1,0,0,2])
     154        sage: G2 = LocalGenusSymbol(A, 2)
     155        sage: is_2_adic_genus(G2.symbol_tuple_list())
     156        True
    71157    """
    72     for s in symbol:
     158    ## TO DO: Add explicit checking for the prime p here to ensure it's p=2... not just the quintuple checking below
     159
     160    for s in genus_symbol_quintuple_list:
     161
     162        ## Check that we have a quintuple (i.e. that p=2 and not p >2)
     163        if len(s) != 5:
     164            raise TypeError, "The genus symbols are not quintuples, so it's not a genus symbol for the prime p=2."
     165
     166        ## Check the Conway-Sloane conditions
    73167        if s[1] == 1:
    74168            if s[3] == 0 or s[2] != s[4]:
    75169                return False
     
    86180            return False
    87181    return True
    88182
    89 def canonical_2_adic_compartments(symbol):
     183
     184
     185def canonical_2_adic_compartments(genus_symbol_quintuple_list):
    90186    """
    91     See Conway-Sloane, pp. 382-383.
     187    Given a 2-adic local symbol (as the underlying list of quintuples)
     188    this returns a list of lists of indices of the
     189    genus_symbol_quintuple_list which are in the same compartment.  A
     190    compartment is defined to be a maximal interval of Jordan
     191    components all (scaled) of type I (i.e. odd).
     192
     193    INPUT:
     194        genus_symbol_quintuple_list -- a quintuple of integers (with certain
     195        rectrictions).
     196
     197    OUTPUT:
     198        a list of lists of integers.
     199
     200    EXAMPLES:
     201        sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
     202        sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_compartments
     203
     204        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     205        sage: G2 = LocalGenusSymbol(A, 2); G2
     206        Genus symbol at 2 : [[0, 2, 1, 1, 2]]
     207        sage: canonical_2_adic_compartments(G2.symbol_tuple_list())
     208        [[0]]
     209
     210        sage: A = Matrix(ZZ, 2, 2, [1,0,0,2])
     211        sage: G2 = LocalGenusSymbol(A, 2); G2
     212        Genus symbol at 2 : [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     213        sage: canonical_2_adic_compartments(G2.symbol_tuple_list())
     214        [[0, 1]]
     215
     216        sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     217        sage: G2 = LocalGenusSymbol(A, 2); G2
     218        Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     219        sage: canonical_2_adic_compartments(G2.symbol_tuple_list())
     220        [[0, 1, 2]]
     221
     222        sage: A = Matrix(ZZ, 2, 2, [2,1,1,2])
     223        sage: G2 = LocalGenusSymbol(A, 2); G2
     224        Genus symbol at 2 : [[0, 2, 3, 0, 0]]
     225        sage: canonical_2_adic_compartments(G2.symbol_tuple_list())   ## No compartments here!
     226        []
     227
     228    NOTES:
     229        See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples.
    92230    """
     231    symbol = genus_symbol_quintuple_list
    93232    compartments = []
    94233    i = 0
    95234    r = len(symbol)
     
    106245        else:   
    107246            i += 1
    108247    return compartments
     248
     249
     250
     251
    109252   
    110 def canonical_2_adic_trains(symbol, compartments):
     253def canonical_2_adic_trains(genus_symbol_quintuple_list, compartments=None):
    111254    """
    112     See Conway-Sloane, pp. 382-383.
     255    Given a 2-adic local symbol (as the underlying list of quintuples)
     256    this returns a list of lists of indices of the
     257    genus_symbol_quintuple_list which are in the same train.  A train
     258    is defined to be a maximal interval of Jordan components so that
     259    at least one of each adjacent pair (allowing zero-dimensional
     260    Jordan components) is (scaled) of type I (i.e. odd).
     261
     262    INPUT:
     263        genus_symbol_quintuple_list -- a quintuple of integers (with certain
     264                             rectrictions).
     265        compartments -- a list of lists of distict integers (optional)
     266
     267    OUTPUT:
     268        a list of lists of distinct integers.
     269
     270    EXAMPLES:
     271        sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
     272        sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_compartments
     273        sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_trains
     274
     275        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     276        sage: G2 = LocalGenusSymbol(A, 2); G2
     277        Genus symbol at 2 : [[0, 2, 1, 1, 2]]
     278        sage: c = canonical_2_adic_compartments(G2.symbol_tuple_list()); c
     279        [[0]]
     280        sage: canonical_2_adic_trains(G2.symbol_tuple_list(), c)
     281        [[0]]
     282
     283        sage: A = Matrix(ZZ, 2, 2, [1,0,0,2])
     284        sage: G2 = LocalGenusSymbol(A, 2); G2
     285        Genus symbol at 2 : [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     286        sage: c = canonical_2_adic_compartments(G2.symbol_tuple_list()); c
     287        [[0, 1]]
     288        sage: canonical_2_adic_trains(G2.symbol_tuple_list(), c)
     289        [[0, 1]]
     290        sage: canonical_2_adic_trains(G2.symbol_tuple_list())
     291        [[0, 1]]
     292
     293        sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     294        sage: G2 = LocalGenusSymbol(A, 2); G2
     295        Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     296        sage: c = canonical_2_adic_compartments(G2.symbol_tuple_list()); c
     297        [[0, 1, 2]]
     298        sage: canonical_2_adic_trains(G2.symbol_tuple_list())
     299        [[0, 1, 2]]
     300
     301        sage: A = Matrix(ZZ, 2, 2, [2,1,1,2])
     302        sage: G2 = LocalGenusSymbol(A, 2); G2
     303        Genus symbol at 2 : [[0, 2, 3, 0, 0]]
     304        sage: c = canonical_2_adic_compartments(G2.symbol_tuple_list()); c   ## No compartments here!
     305        []
     306        sage: canonical_2_adic_trains(G2.symbol_tuple_list())
     307        []
     308
     309    NOTES:
     310        See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples.
     311
     312    TO DO: 
     313        - Add a non-trivial example in the doctest here!
    113314    """
     315    ## Recompte compartments if none are passed.
     316    if compartments == None:
     317        compartments = canonical_2_adic_compartments(genus_symbol_quintuple_list)
     318
     319    symbol = genus_symbol_quintuple_list
    114320    trains = []
    115321    i = 0
    116322    while i < len(compartments):
     
    138344        trains.append(train)
    139345    return trains
    140346
    141 def canonical_2_adic_reduction(symbol):
     347
     348
     349
     350def canonical_2_adic_reduction(genus_symbol_quintuple_list):
    142351    """
     352    Given a 2-adic local symbol (as the underlying list of quintuples)
     353    this returns a canonical 2-adic symbol (again as a raw list of
     354    quintuples of integers) which has at most one minus sign per train
     355    and this sign appears on the smallest dimensional Jordan component
     356    in each train.  This results from applying the "sign-walking" and
     357    "oddity fusion" equivalences.
     358
     359    INPUT:
     360        genus_symbol_quintuple_list -- a quintuple of integers (with certain
     361                             rectrictions).
     362        compartments -- a list of lists of distict integers (optional)
     363
     364    OUTPUT:
     365        a list of lists of distinct integers.
     366
     367    EXAMPLES:
     368        sage: from sage.quadratic_forms.genera.genus import LocalGenusSymbol
     369        sage: from sage.quadratic_forms.genera.genus import canonical_2_adic_reduction
     370
     371        sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     372        sage: G2 = LocalGenusSymbol(A, 2); G2
     373        Genus symbol at 2 : [[0, 2, 1, 1, 2]]
     374        sage: canonical_2_adic_reduction(G2.symbol_tuple_list())
     375        [[0, 2, 1, 1, 2]]
     376
     377        sage: A = Matrix(ZZ, 2, 2, [1,0,0,2])
     378        sage: G2 = LocalGenusSymbol(A, 2); G2
     379        Genus symbol at 2 : [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     380        sage: canonical_2_adic_reduction(G2.symbol_tuple_list())   ## Oddity fusion occurred here!
     381        [[0, 1, 1, 1, 2], [1, 1, 1, 1, 0]]
     382
     383        sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     384        sage: G2 = LocalGenusSymbol(A, 2); G2
     385        Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     386        sage: canonical_2_adic_reduction(G2.symbol_tuple_list())   ## Oddity fusion occurred here!
     387        [[1, 2, -1, 1, 6], [2, 1, 1, 1, 0], [3, 1, 1, 1, 0]]
     388
     389        sage: A = Matrix(ZZ, 2, 2, [2,1,1,2])
     390        sage: G2 = LocalGenusSymbol(A, 2); G2
     391        Genus symbol at 2 : [[0, 2, 3, 0, 0]]
     392        sage: canonical_2_adic_reduction(G2.symbol_tuple_list())
     393        [[0, 2, -1, 0, 0]]
     394
     395    NOTES:
     396        See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples.
     397
     398    TO DO: 
     399        - Add an example where sign walking occurs!
    143400    """
    144     canonical_symbol = symbol
     401    canonical_symbol = genus_symbol_quintuple_list
    145402    # Canonical determinants:
    146     for i in range(len(symbol)):
    147         d = symbol[i][2]
     403    for i in range(len(genus_symbol_quintuple_list)):
     404        d = genus_symbol_quintuple_list[i][2]
    148405        if d in (1,7):
    149406            canonical_symbol[i][2] = 1
    150407        else:
    151408            canonical_symbol[i][2] = -1
    152409    # Oddity fusion:
    153     compartments = canonical_2_adic_compartments(symbol)
     410    compartments = canonical_2_adic_compartments(genus_symbol_quintuple_list)
    154411    for compart in compartments:
    155         oddity = sum([ symbol[i][4] for i in compart ]) % 8
     412        oddity = sum([ genus_symbol_quintuple_list[i][4] for i in compart ]) % 8
    156413        for i in compart:
    157             symbol[i][4] = 0
    158         symbol[compart[0]][4] = oddity
     414            genus_symbol_quintuple_list[i][4] = 0
     415        genus_symbol_quintuple_list[compart[0]][4] = oddity
    159416    #print "End oddity fusion:", canonical_symbol
    160417    # Sign walking:     
    161     trains = canonical_2_adic_trains(symbol, compartments)
     418    trains = canonical_2_adic_trains(genus_symbol_quintuple_list, compartments)
    162419    for train in trains:
    163420        t = len(train)
    164421        for i in range(t-1):
     
    173430    #print "End sign walking:", canonical_symbol
    174431    return canonical_symbol
    175432
     433
     434
     435
     436
    176437def basis_complement(B):
    177438    """
    178     Given an echelonized basis matrix (over a field),
    179     calculate a matrix whose rows form a basis complement.
     439    Given an echelonized basis matrix (over a field), calculate a
     440    matrix whose rows form a basis complement (to the rows of B).
     441
     442    INPUT:
     443        B -- matrix over a field in row echelon form
     444
     445    OUTPUT:
     446        a rectangular matrix over a field
     447
     448    EXAMPLES:
     449        sage: from sage.quadratic_forms.genera.genus import basis_complement
     450
     451        sage: A = Matrix(ZZ, 2, 2, [1,1,1,1])
     452        sage: B = A.kernel().echelonized_basis_matrix(); B
     453        [ 1 -1]
     454        sage: basis_complement(B)
     455        [0 1]
    180456    """
    181457    F = B.parent().base_ring() 
    182458    m = B.nrows()       
     
    196472        C[l+j-k,j] = 1
    197473    return C
    198474
    199 def signature_of_matrix(A):
     475
     476
     477def signature_pair_of_matrix(A):
    200478    """
    201     The signature of a non-degenerate symmetric matrix.
     479    Computes the signature pair (p, n) of a non-degenerate symmetric
     480    matrix, where
     481        p = number of positive eigenvalues of A
     482        n = number of negative eigenvalues of A
    202483
    203     TODO: Implement a better algorithm.
     484    INPUT:
     485        A -- symmetric matrix (assumed to be non-degenerate)
     486
     487    OUTPUT:
     488        a pair (tuple) of integers.
     489
     490    EXAMPLES:
     491        sage: from sage.quadratic_forms.genera.genus import signature_pair_of_matrix
     492
     493        sage: A = Matrix(ZZ, 2, 2, [-1,0,0,3])
     494        sage: signature_pair_of_matrix(A)
     495        (1, 1)
     496
     497        sage: A = Matrix(ZZ, 2, 2, [-1,1,1,7])
     498        sage: signature_pair_of_matrix(A)
     499        (1, 1)
     500
     501        sage: A = Matrix(ZZ, 2, 2, [3,1,1,7])
     502        sage: signature_pair_of_matrix(A)
     503        (2, 0)
     504
     505        sage: A = Matrix(ZZ, 2, 2, [-3,1,1,-11])
     506        sage: signature_pair_of_matrix(A)
     507        (0, 2)
     508
     509
     510        sage: A = Matrix(ZZ, 2, 2, [1,1,1,1])
     511        sage: signature_pair_of_matrix(A)     ## Raises an error -- degenerate matrix
     512        Traceback (most recent call last):
     513        ...
     514        TypeError: A is assumed to be non-degenerate, but it's det = 0.       
     515
    204516    """
    205     r = 0
    206     s = 0
    207     e0 = 1
    208     for i in range(A.nrows()):
    209         # Argh!...
    210         e1 = RealField()(A[0:i+1, 0:i+1].determinant()).sign()
    211         if e0*e1 == 1:
    212            r += 1
    213         else:           
    214            s += 1
    215         e0 = e1
    216     return (r, s)
     517    from sage.quadratic_forms.quadratic_form import QuadraticForm
     518    s_vec = QuadraticForm(A.base_extend(A.base_ring().fraction_field())).signature_vector()
    217519
    218 def p_adic_symbol(A,p,val):
     520    ## Check that the matrix is non-degenerate (i.e. no zero eigenvalues)
     521    if s_vec[2] != 0:
     522        raise TypeError, "A is assumed to be non-degenerate, but it's det = 0."
     523
     524    ## Return the pair (p,n)
     525    return s_vec[:2]
     526   
     527
     528
     529def p_adic_symbol(A, p, val):
    219530    """
    220531    Given a symmetric matrix A and prime p, return the genus symbol at p.
     532
    221533    val = valuation of the maximal elementary divisor of A
    222534    needed to obtain enough precision
    223535    calculation is modulo p to the val+3
    224536    TODO: Some description of the definition of the genus symbol.
     537
     538    INPUT:
     539        A -- symmetric matrix with integer coefficients
     540        p -- prime number > 0
     541        val -- integer >= 0
     542
     543    OUTPUT:
     544        a list of lists of integers
     545
     546    EXAMPLES:
     547        sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     548
     549        sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     550        sage: p_adic_symbol(A, 2, 2)
     551        [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     552
     553        sage: p_adic_symbol(A, 3, 1)
     554        [[0, 3, 1], [1, 1, -1]]
     555
    225556    """
    226557    if p % 2 == 0:
    227558        return two_adic_symbol(A, val)
     
    258589    A = B*(A - X.transpose()*U*X)*B.transpose()
    259590    return [ [s[0]+m0] + s[1:] for s in sym + p_adic_symbol(A, p, val) ]
    260591
    261 def is_even(A):
     592
     593
     594def is_even_matrix(A):
     595    """
     596    Determines if the integral symmetric matrix A is even
     597    (i.e. represents only even numbers).  If not, then it returns the
     598    index of an odd diagonal entry.  If it is even, then we return the
     599    index -1.
     600
     601    INPUT:
     602        A -- symmetric integer matrix
     603
     604    OUTPUT:
     605        a pair of the form (boolean, integer)
     606
     607    EXAMPLES:
     608        sage: from sage.quadratic_forms.genera.genus import is_even_matrix
     609
     610        sage: A = Matrix(ZZ, 2, 2, [1,1,1,1])
     611        sage: is_even_matrix(A)
     612        (False, 0)
     613
     614        sage: A = Matrix(ZZ, 2, 2, [2,1,1,2]) 
     615        sage: is_even_matrix(A)
     616        (True, -1)
     617    """
    262618    for i in range(A.nrows()):
    263619        if A[i,i]%2 == 1:
    264620            return False, i
    265621    return True, -1
    266622
     623
     624
    267625def split_odd(A):
    268626    """
    269     Given a Gram matrix A (mod 8), return a splitting [u] + B
     627    Given a non-degenerate Gram matrix A (mod 8), return a splitting [u] + B
    270628    such that u is odd and B is not even.
     629
     630    INPUT:
     631        A -- an odd symmetric matrix with integer coefficients (which
     632        admits a splitting as above).
     633
     634    OUTPUT:
     635        a pair (u, B) consisting of an odd integer u and an odd
     636        integral symmetric matrix B.
     637
     638    EXAMPLES:
     639        sage: from sage.quadratic_forms.genera.genus import is_even_matrix
     640        sage: from sage.quadratic_forms.genera.genus import split_odd
     641
     642        sage: A = Matrix(ZZ, 2, 2, [1,2,2,3]) 
     643        sage: is_even_matrix(A)
     644        (False, 0)
     645        sage: split_odd(A)
     646        (1, [-1])
     647
     648        sage: A = Matrix(ZZ, 2, 2, [1,2,2,5])
     649        sage: split_odd(A)
     650        (1, [1])
     651
     652        sage: A = Matrix(ZZ, 2, 2, [1,1,1,1])
     653        sage: is_even_matrix(A)
     654        (False, 0)
     655        sage: split_odd(A)      ## This fails because no such splitting exists. =(
     656        Traceback (most recent call last):
     657        ...
     658        RuntimeError: The matrix A does not admit a non-even splitting.
     659
     660        sage: A = Matrix(ZZ, 2, 2, [1,2,2,6])
     661        sage: split_odd(A)      ## This fails because no such splitting exists. =(
     662        Traceback (most recent call last):
     663        ...
     664        RuntimeError: The matrix A does not admit a non-even splitting.
     665
    271666    """
    272667    n0 = A.nrows()
    273668    if n0 == 1:
    274669       return A[0,0], MatrixSpace(IntegerRing(),0,A.ncols())([])
    275     even, i = is_even(A)
     670    even, i = is_even_matrix(A)
    276671    R = A.parent().base_ring()
    277672    C = MatrixSpace(R,n0-1,n0)(0)
    278673    u = A[i,i]
     
    284679            C[j,j+1] = 1
    285680            C[j,i] = -A[j+1,i]*u
    286681        B = C*A*C.transpose()
    287     even, j = is_even(B)
     682    even, j = is_even_matrix(B)
    288683    if even:
    289684        I = A.parent()(1)
    290685        # TODO: we could manually (re)construct the kernel here...
     
    305700                C[j,j+1] = 1
    306701                C[j,i] = -A[j+1,i]*u
    307702            B = C*A*C.transpose()
    308     even, j = is_even(B)
     703    even, j = is_even_matrix(B)
    309704    if even:
    310705        print "B:"
    311706        print B
    312         assert False
     707        raise RuntimeError, "The matrix A does not admit a non-even splitting."
    313708    return u, B
    314709
    315 def trace_diag(A):
     710
     711
     712def trace_diag_mod_8(A):
    316713    """
    317     Return the trace of the diagonalised form of A.
     714    Return the trace of the diagonalised form of A of an integral
     715    symmetric matrix which is diagonalizable mod 8.  (Note that since
     716    the Jordan decomposition into blocks of size <= 2 is not unique
     717    here, this is not the same as saying that A is always diagonal in
     718    any 2-adic Jordan decomposition!)
     719
     720    INPUT:
     721        A -- symmetric matrix with coefficients in Z which is odd in
     722        Z/2Z and has determinant not divisible by 8.
     723
     724    OUTPUT:
     725        an integer
     726
     727    EXAMPLES:
     728        sage: from sage.quadratic_forms.genera.genus import is_even_matrix
     729        sage: from sage.quadratic_forms.genera.genus import split_odd
     730        sage: from sage.quadratic_forms.genera.genus import trace_diag_mod_8
     731
     732        sage: A = Matrix(ZZ, 2, 2, [1,2,2,3]) 
     733        sage: is_even_matrix(A)
     734        (False, 0)
     735        sage: split_odd(A)
     736        (1, [-1])
     737        sage: trace_diag_mod_8(A)
     738        0
     739
     740        sage: A = Matrix(ZZ, 2, 2, [1,2,2,5])
     741        sage: split_odd(A)
     742        (1, [1])
     743        sage: trace_diag_mod_8(A)
     744        2       
    318745    """
    319746    tr = 0
    320747    while A.nrows() > 0:
     
    323750    return IntegerRing()(tr)
    324751
    325752
     753
    326754def two_adic_symbol(A, val):
    327755    """
    328756    Given a symmetric matrix A and prime p, return the genus symbol at p.
     
    336764        d = det(f) in {1,3,5,7}
    337765        s = 0 (or 1) if even (or odd)
    338766        o = oddity of f (= 0 if s = 0) in Z/8Z
     767
     768    INPUT:
     769        A -- symmetric matrix with integer coefficients
     770        val -- integer >=0
     771
     772    OUTPUT:
     773        a list of lists of integers (representing a Conway-Sloane 2-adic symbol)
     774
     775    EXAMPLES:
     776        sage: from sage.quadratic_forms.genera.genus import two_adic_symbol
     777
     778        sage: A = diagonal_matrix(ZZ, [1,2,3,4])
     779        sage: two_adic_symbol(A, 2)
     780        [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]
     781
    339782    """
    340783    m0 = min([ c.valuation(2) for c in A.list() ])
    341784    q = 2**m0
     
    345788    A_2 = MatrixSpace(FiniteField(2),n,n)(A)   
    346789    K_2 = A_2.kernel()
    347790    R_8 = ZZ.quotient_ring(Integer(8))
     791
     792    ## Deal with the matrix being non-degenerate mod 2.
    348793    if K_2.dimension() == 0:
    349794        A_8 = MatrixSpace(R_8,n)(A)
    350795        n0 = A.nrows() 
    351796        # d0 = ZZ(A_8.determinant()) # no determinant over Z/8Z
    352797        d0 = ZZ(R_8(MatrixSpace(ZZ,n)(A_8).determinant()))
    353         if d0 == 0:
     798        if d0 == 0:    ## SANITY CHECK: The mod 8 determinant shouldn't be zero.
    354799            print "A:"
    355800            print A
    356801            assert False
    357         even, i = is_even(A_2)
     802        even, i = is_even_matrix(A_2)    ## Determine whether the matrix is even or odd.
    358803        if even:
    359804            return [ [m0,n0,d0,0,0] ]
    360805        else:
    361             tr8 = trace_diag(A_8)
     806            tr8 = trace_diag_mod_8(A_8)  ## Here we already know that A_8 is odd and diagonalizable mod 8.
    362807            return [ [m0,n0,d0,1,tr8] ]
     808
     809    ## Deal with the matrix being degenerate mod 2.
    363810    else:
    364811        B_2 = K_2.echelonized_basis_matrix()
    365812        C_2 = basis_complement(B_2)   
     
    374821            print "A:"
    375822            print A_new
    376823            assert False
    377         even, i = is_even(A_new)
     824        even, i = is_even_matrix(A_new)
    378825        if even:
    379826            sym = [ [0,n0,d0,0,0] ]
    380827        else:
    381             tr8 = trace_diag(A_8)
     828            tr8 = trace_diag_mod_8(A_8)
    382829            sym = [ [0,n0,d0,1,tr8] ]
    383830    r = B_2.nrows()
    384831    B = MatrixSpace(ZZ,r,n)(B_2)
     
    395842    A = B*(A - X.transpose()*U*X)*B.transpose()
    396843    return [ [s[0]+m0] + s[1:] for s in sym + two_adic_symbol(A, val) ]
    397844
    398 def is_trivial_symbol(p, sym):
    399     if len(sym) != 1:
    400         return False
    401     if sym[0] != 0 or sym[2] != 1:
    402         return False
    403     if p != 2:
    404         return True
    405     return sym[3] == 1 and sym[1] % 8 == sym[4]
     845
     846
     847
     848
     849## Removed because it was unused and undocumented!
     850#
     851#def is_trivial_symbol(p, sym):
     852#    """
     853#    """
     854#    if len(sym) != 1:
     855#        return False
     856#    if sym[0] != 0 or sym[2] != 1:
     857#        return False
     858#    if p != 2:
     859#        return True
     860#    return sym[3] == 1 and sym[1] % 8 == sym[4]
     861
     862
     863
     864
     865
     866
     867
    406868
    407869class Genus_Symbol_p_adic_ring(object):
    408870    """
     
    412874        """
    413875        Create the local genus symbol of given prime and local invariants.
    414876
    415         INPUT:
    416              prime -- the prime
    417              symbol -- the list of invariants for Jordan blocks A_t,...,A_t
    418              
    419877        The genus symbol of a component p^m*A for odd prime = p is of the
    420878        form (m,n,d), where
    421879
     
    436894        The genus symbol is a list of such symbols (ordered by m) for each
    437895        of the Jordan blocks A_1,...,A_t.
    438896
    439         Reference: Conway and Sloane, Chapter 9.
     897        Reference: Conway and Sloane 3rd edition, Chapter 15, Section 7.
     898
     899
     900        WARNING/NOTE: This normalization seems non-standard, and we
     901        should review this entire class to make sure that we have our
     902        doubling conventions strraight throughout!  This is especially
     903        noticeable in the determinant and excess methods!!
     904
     905
     906        INPUT:
     907            prime -- a prime integer > 0
     908            symbol -- the list of invariants for Jordan blocks
     909                      A_t,...,A_t given as a list of lists of integers
     910
     911        OUTPUT:
     912            None
     913
     914        EXAMPLES:
     915            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     916            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     917
     918            sage: A = diagonal_matrix(ZZ, [1,2,3,4])
     919            sage: p = 2
     920            sage: s2 = p_adic_symbol(A, p, 2); s2
     921            [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]   
     922            sage: Genus_Symbol_p_adic_ring(p, s2)
     923            Genus symbol at 2 : [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]
     924
     925            sage: A = diagonal_matrix(ZZ, [1,2,3,4])
     926            sage: p = 3
     927            sage: s3 = p_adic_symbol(A, p, 1); s3
     928            [[0, 3, -1], [1, 1, 1]]
     929            sage: Genus_Symbol_p_adic_ring(p, s3)
     930            Genus symbol at 3 : [[0, 3, -1], [1, 1, 1]]
     931
    440932        """
    441933        if check:
    442934           pass
     
    445937        self._canonical_symbol = None
    446938
    447939    def __repr__(self):
     940        """
     941        Gives a string representation for the p-adic genus symbol
     942
     943        INPUT:
     944            None
     945
     946        OUTPUT:
     947            a string
     948
     949        EXAMPLES:
     950            sage: from sage.quadratic_forms.genera.genus import two_adic_symbol
     951            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     952
     953            sage: A = diagonal_matrix(ZZ, [1,2,3,4])
     954            sage: s2 = two_adic_symbol(A, 2); s2
     955            [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]   
     956            sage: G = Genus_Symbol_p_adic_ring(2, s2)
     957            sage: G.__repr__()
     958            'Genus symbol at 2 : [[0, 2, 3, 1, 4], [1, 1, 1, 1, 1], [2, 1, 1, 1, 1]]'
     959
     960        """
    448961        return "Genus symbol at %s : %s"%(self._prime, self._symbol)
    449962
    450     def __eq__(self,other):
     963
     964    def __eq__(self, other):
     965        """
     966        Determines if two genus symbols are equal (not just equivalent!).
     967
     968        INPUT:
     969            a Genus_Symbol_p_adic_ring object
     970
     971        OUTPUT:
     972            boolean
     973
     974        EXAMPLES:
     975            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     976            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     977
     978            sage: A = diagonal_matrix(ZZ, [1,2,3,4])
     979            sage: p = 2
     980            sage: G2 =  Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2))
     981            sage: p = 3
     982            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 1))
     983
     984            sage: G2 == G3
     985            False
     986            sage: G3 == G2
     987            False
     988            sage: G2 == G2
     989            True
     990            sage: G3 == G3
     991            True
     992
     993        """
    451994        p = self._prime
    452995        if p != other._prime:
    453996            return False
    454997        return self.canonical_symbol() == other.canonical_symbol()
    455998
    456     def __ne__(self,other):
     999
     1000    def __ne__(self, other):
     1001        """
     1002        Determines if two genus symbols are unequal (not just inequivalent!).
     1003
     1004        INPUT:
     1005            a Genus_Symbol_p_adic_ring object
     1006
     1007        OUTPUT:
     1008            boolean
     1009
     1010            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1011            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1012
     1013            sage: A = diagonal_matrix(ZZ, [1,2,3,4])
     1014            sage: p = 2
     1015            sage: G2 =  Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2))
     1016            sage: p = 3
     1017            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 1))
     1018
     1019            sage: G2 != G3
     1020            True
     1021            sage: G3 != G2
     1022            True
     1023            sage: G2 != G2
     1024            False
     1025            sage: G3 != G3
     1026            False
     1027
     1028        """
    4571029        return not self.__eq__(other)
    4581030
     1031
     1032    ## Added these two methods to make this class iterable...
     1033    #def  __getitem__(self, i):
     1034    #    return self._symbol[i]
     1035    #
     1036    #def len(self):
     1037    #    return len(self._symbol)
     1038    ## ------------------------------------------------------
     1039
     1040
    4591041    def canonical_symbol(self):
     1042        """
     1043        Return (and cache) the canonial p-adic genus symbol.  This is
     1044        only really affects the 2-adic symbol, since when p > 2 the
     1045        symbol is already canonical.
     1046
     1047        INPUT:
     1048            None
     1049
     1050        OUTPUT:
     1051            a list of lists of integers
     1052
     1053        EXAMPLES:
     1054            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1055            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1056
     1057            sage: A = Matrix(ZZ, 2, 2, [1,1,1,2])
     1058            sage: p = 2
     1059            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1060            Genus symbol at 2 : [[0, 2, 1, 1, 2]]
     1061            sage: G2.canonical_symbol()
     1062            [[0, 2, 1, 1, 2]]
     1063
     1064            sage: A = Matrix(ZZ, 2, 2, [1,0,0,2])
     1065            sage: p = 2
     1066            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1067            Genus symbol at 2 : [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
     1068            sage: G2.canonical_symbol()   ## Oddity fusion occurred here!
     1069            [[0, 1, 1, 1, 2], [1, 1, 1, 1, 0]]
     1070
     1071            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1072            sage: p = 2
     1073            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1074            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1075            sage: G2.canonical_symbol()   ## Oddity fusion occurred here!
     1076            [[1, 2, -1, 1, 6], [2, 1, 1, 1, 0], [3, 1, 1, 1, 0]]
     1077
     1078            sage: A = Matrix(ZZ, 2, 2, [2,1,1,2])
     1079            sage: p = 2
     1080            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1081            Genus symbol at 2 : [[0, 2, 3, 0, 0]]
     1082            sage: G2.canonical_symbol()
     1083            [[0, 2, -1, 0, 0]]
     1084
     1085
     1086            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1087            sage: p = 3
     1088            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3
     1089            Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     1090            sage: G3.canonical_symbol() 
     1091            [[0, 3, 1], [1, 1, -1]]
     1092
     1093
     1094            NOTES:
     1095                See Conway-Sloane 3rd edition, pp. 381-382 for definitions and examples.
     1096
     1097            TO DO: 
     1098                - Add an example where sign walking occurs!
     1099        """
    4601100        symbol = self._symbol
    4611101        if self._prime == 2:
    4621102            if self._canonical_symbol is None:
     
    4651105        else:
    4661106            return self._symbol
    4671107
    468     def symbol(self):
     1108
     1109
     1110    def symbol_tuple_list(self):
     1111        """
     1112        Returns the underlying list of lists of integers defining the genus symbol.
     1113
     1114        INPUT:
     1115            None
     1116
     1117        OUTPUT:
     1118            list of lists of integers
     1119
     1120        EXAMPLES:
     1121            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1122            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1123
     1124            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1125            sage: p = 3
     1126            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3
     1127            Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     1128            sage: G3.symbol_tuple_list() 
     1129            [[0, 3, 1], [1, 1, -1]]
     1130            sage: type(G3.symbol_tuple_list())
     1131            <type 'list'>
     1132
     1133            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1134            sage: p = 2
     1135            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1136            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1137            sage: G2.symbol_tuple_list() 
     1138            [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1139            sage: type(G2.symbol_tuple_list())
     1140            <type 'list'>
     1141
     1142        """
    4691143        return self._symbol
    4701144
     1145
     1146
    4711147    def number_of_blocks(self):
     1148        """
     1149        Returns the number of positive dimensional symbols/Jordan blocks
     1150
     1151        INPUT:
     1152            None
     1153
     1154        OUTPUT:
     1155            integer >= 0
     1156
     1157        EXAMPLES:
     1158            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1159            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1160
     1161            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1162            sage: p = 2
     1163            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1164            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1165            sage: G2.number_of_blocks() 
     1166            3
     1167
     1168            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1169            sage: p = 3
     1170            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3
     1171            Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     1172            sage: G3.number_of_blocks() 
     1173            2
     1174
     1175        """
    4721176        return len(self._symbol)
    4731177
     1178
    4741179    def determinant(self):
     1180        """
     1181        Returns the (p-part of the) determinant (square-class) of the
     1182        Hessian matrix of the quadratic form (given by regarding the
     1183        integral symmetric matrix which generated this genus symbol as
     1184        the Gram matrix of Q) associated to this local genus symbol.
     1185
     1186        INPUT:
     1187            None
     1188
     1189        OUTPUT:
     1190            an integer
     1191
     1192        EXAMPLES:
     1193            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1194            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1195
     1196            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1197            sage: p = 2
     1198            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1199            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1200            sage: G2.determinant() 
     1201            128
     1202
     1203            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1204            sage: p = 3
     1205            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3
     1206            Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     1207            sage: G3.determinant() 
     1208            3
     1209        """
    4751210        p = self._prime
    4761211        return misc.prod([ p**(s[0]*s[1]) for s in self._symbol ])
    4771212
     1213
    4781214    def rank(self):
     1215        """
     1216        Returns the dimension of a quadratic form associated to this genus symbol.
     1217
     1218        TO DO: DELETE THIS METHOD IN FAVOR OF THE dimension() METHOD BELOW!
     1219
     1220
     1221        INPUT:
     1222            None
     1223
     1224        OUTPUT:
     1225            an integer >= 0
     1226
     1227        EXAMPLES:
     1228            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1229            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1230
     1231            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1232            sage: p = 2
     1233            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1234            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1235            sage: G2.rank() 
     1236            4
     1237
     1238            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1239            sage: p = 3
     1240            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3
     1241            Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     1242            sage: G3.rank() 
     1243            4
     1244
     1245        """
    4791246        return sum([ s[1] for s in self._symbol ])
    4801247
     1248
    4811249    def dimension(self):
     1250        """
     1251        Returns the dimension of a quadratic form associated to this genus symbol.
     1252
     1253        INPUT:
     1254            None
     1255
     1256        OUTPUT:
     1257            an integer >= 0
     1258
     1259        EXAMPLES:
     1260            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1261            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1262
     1263            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1264            sage: p = 2
     1265            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1266            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1267            sage: G2.dimension() 
     1268            4
     1269
     1270            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1271            sage: p = 3
     1272            sage: G3 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G3
     1273            Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     1274            sage: G3.dimension() 
     1275            4
     1276
     1277        """
    4821278        return self.rank()
    4831279
     1280
    4841281    def excess(self):
    4851282        """
    486         The p-excesss in the notation of Conway & Sloane, and the oddity for p = 2. 
     1283        Returns the p-excess of the quadratic form whose Hessian
     1284        matrix is the symmetric matrix A.  When p = 2 the p-excess is
     1285        called the oddity.
     1286
     1287        WARNING/NOTE: This normalization seems non-standard, and we
     1288        should review this entire class to make sure that we have our
     1289        doubling conventions strraight throughout!
     1290
     1291        REFERENCE:
     1292            Conway and Sloane Book, 3rd edition, pp 370-371.
     1293
     1294        INPUT:
     1295            None
     1296
     1297        OUTPUT:
     1298            an integer
     1299
     1300        EXAMPLES:
     1301            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1302            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1303
     1304            sage: AC = diagonal_matrix(ZZ, [1,3,-3])
     1305            sage: p=2; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1306            1
     1307            sage: p=3; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1308            0
     1309            sage: p=5; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1310            0
     1311            sage: p=7; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1312            0
     1313            sage: p=11; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1314            0
     1315
     1316            sage: AC = 2 * diagonal_matrix(ZZ, [1,3,-3])
     1317            sage: p=2; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1318            1
     1319            sage: p=3; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1320            0
     1321            sage: p=5; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1322            0
     1323            sage: p=7; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1324            0
     1325            sage: p=11; Genus_Symbol_p_adic_ring(p, p_adic_symbol(AC, p, 2)).excess()
     1326            0
     1327
     1328            sage: A = 2*diagonal_matrix(ZZ, [1,2,3,4])
     1329            sage: p=2; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess()
     1330            2
     1331            sage: p=3; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess()
     1332            6
     1333            sage: p=5; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess()
     1334            0
     1335            sage: p=7; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess()
     1336            0
     1337            sage: p=11; Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)).excess()
     1338            0
     1339
    4871340        """
    4881341        p = self._prime
    4891342        if self._prime == 2:
     
    4991352                   k += 1
    5001353           return Integer(sum([ s[1]*(p**s[0]-1) for s in self._symbol ]) + 4*k).mod(8)
    5011354
     1355
     1356
    5021357    def trains(self):
    503         assert self._prime == 2
     1358        """
     1359        Compute the indices for each of the trains in this local genus
     1360        symbol if it is associated to the prime p=2 (and raise an
     1361        error for all other primes).
     1362
     1363        INPUT:
     1364            None
     1365
     1366        OUTPUT:
     1367            a list of integers >= 0
     1368
     1369        EXAMPLES:
     1370            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1371            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1372
     1373            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1374            sage: p = 2
     1375            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1376            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1377            sage: G2.trains()
     1378            [[0, 1, 2]]
     1379
     1380        """
     1381        ## Check that p = 2
     1382        if self._prime != 2:
     1383            raise TypeError, "trains() only mkes sense when the prime of the p_adic_Genus_Symbol is p=2"
    5041384        symbol = self._symbol
    5051385        compartments = canonical_2_adic_compartments(symbol)
    5061386        return canonical_2_adic_trains(symbol, compartments)
    5071387
     1388
    5081389    def compartments(self):
    509         assert self._prime == 2
     1390        """
     1391        Compute the indices for each of the compartments in this local genus
     1392        symbol if it is associated to the prime p=2 (and raise an
     1393        error for all other primes).
     1394
     1395        INPUT:
     1396            None
     1397
     1398        OUTPUT:
     1399            a list of integers >= 0
     1400
     1401        EXAMPLES:
     1402            sage: from sage.quadratic_forms.genera.genus import p_adic_symbol
     1403            sage: from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring
     1404
     1405            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1406            sage: p = 2
     1407            sage: G2 = Genus_Symbol_p_adic_ring(p, p_adic_symbol(A, p, 2)); G2
     1408            Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     1409            sage: G2.compartments()
     1410            [[0, 1, 2]]
     1411
     1412        """
     1413        ## Check that p = 2
     1414        if self._prime != 2:
     1415            raise TypeError, "compartments() only mkes sense when the prime of the p_adic_Genus_Symbol is p=2"
    5101416        symbol = self._symbol
    5111417        return canonical_2_adic_compartments(symbol)
    5121418
    5131419
    514 class Genus_Symbol_global_ring(object):
     1420
     1421
     1422
     1423
     1424class GenusSymbol_global_ring(object):
    5151425    """
    516     The genus of an integral lattice.
     1426    This represents a collection of local genus symbols (at primes)
     1427    and signature information which represent the genus of a
     1428    non-degenerate integral lattice.
    5171429    """
     1430
    5181431    def __init__(self, A, max_elem_divisors=None):
    5191432        """
    520         Input precision max_elem_divisors for valuation of maximal p-elementary divisor.
     1433        Initialize a global genus symbol from a non-degenerate
     1434        integral gram matrix (and possibly information about its
     1435        largest elementary divisors).
     1436
     1437        INPUT:
     1438            A -- a symmetric matrix with integer coefficients
     1439            max_elem_divisors -- the input precision for valuation of
     1440                                 maximal p-elementary divisor. (OPTIONAL)
     1441
     1442        OUTPUT:
     1443            None
     1444
     1445        EXAMPLES:       
     1446            sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     1447
     1448            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1449            sage: GenusSymbol_global_ring(A)
     1450            Genus of [2 0 0 0]
     1451            [0 4 0 0]
     1452            [0 0 6 0]
     1453            [0 0 0 8]
     1454
    5211455        """
    5221456        D = A.determinant()
    5231457        D = 2*D
    5241458        prms = [ p[0] for p in D.factor() ]
    5251459        self._representative = A
    526         self._signature = signature_of_matrix(A)
     1460        self._signature = signature_pair_of_matrix(A)
    5271461        self._local_symbols = []
    5281462        for p in prms:
    5291463            if max_elem_divisors is None:
     
    5321466            G = Genus_Symbol_p_adic_ring(p, symbol)             
    5331467            self._local_symbols.append(G)
    5341468
     1469
    5351470    def __repr__(self):
     1471        """
     1472        Returns a string representing the global genus symbol.
     1473
     1474        INPUT:
     1475            None
     1476
     1477        OUTPUT:
     1478            a string
     1479
     1480        EXAMPLES:       
     1481            sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     1482
     1483            sage: A = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1484            sage: GS = GenusSymbol_global_ring(A)
     1485            sage: GS.__repr__()
     1486            'Genus of [2 0 0 0]\n[0 4 0 0]\n[0 0 6 0]\n[0 0 0 8]'
     1487
     1488        """
    5361489        return "Genus of %s"%self._representative
    5371490
     1491
     1492
    5381493    def __eq__(self, other):
     1494        """
     1495        Determines if two global genus symbols are equal (not just equivalent!).
     1496
     1497        INPUT:
     1498            a GenusSymbol_global_ring object
     1499
     1500        OUTPUT:
     1501            boolean
     1502
     1503        EXAMPLES:       
     1504            sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     1505
     1506            sage: A1 = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1507            sage: GS1 = GenusSymbol_global_ring(A1)
     1508            sage: A2 = DiagonalQuadraticForm(ZZ, [1,2,3,5]).Hessian_matrix()
     1509            sage: GS2 = GenusSymbol_global_ring(A2)
     1510
     1511            sage: GS1 == GS2
     1512            False
     1513
     1514            sage: GS2 == GS1
     1515            False
     1516
     1517            sage: GS1 == GS1
     1518            True
     1519
     1520            sage: GS2 == GS2
     1521            True
     1522
     1523        """
    5391524        if self is other:
    5401525            return True
    5411526        t = len(self._local_symbols)
     
    5461531                return False
    5471532        return True
    5481533
     1534
     1535
    5491536    def __ne__(self, other):
     1537        """
     1538        Determines if two global genus symbols are unequal (not just inequivalent!).
     1539
     1540        INPUT:
     1541            a GenusSymbol_global_ring object
     1542
     1543        OUTPUT:
     1544            boolean
     1545
     1546        EXAMPLES:       
     1547            sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     1548
     1549            sage: A1 = DiagonalQuadraticForm(ZZ, [1,2,3,4]).Hessian_matrix()
     1550            sage: GS1 = GenusSymbol_global_ring(A1)
     1551            sage: A2 = DiagonalQuadraticForm(ZZ, [1,2,3,5]).Hessian_matrix()
     1552            sage: GS2 = GenusSymbol_global_ring(A2)
     1553
     1554            sage: GS1 != GS2
     1555            True
     1556
     1557            sage: GS2 != GS1
     1558            True
     1559
     1560            sage: GS1 != GS1
     1561            False
     1562
     1563            sage: GS2 != GS2
     1564            False
     1565
     1566        """
    5501567        return not self.__eq__(other)
    5511568
    552     def signature_of_matrix(self):
     1569
     1570    def signature_pair_of_matrix(self):
     1571        """
     1572        Returns the signature pair (p, n) of the (non-degenerate)
     1573        global genus symbol, where p is the number of positive
     1574        eigenvlaues and n is the number of negative eigenvalues.
     1575
     1576        INPUT:
     1577            None
     1578
     1579        OUTPUT:
     1580            a pair of integers (p, n) each >= 0
     1581
     1582        EXAMPLES:
     1583            sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     1584
     1585            sage: A = DiagonalQuadraticForm(ZZ, [1,-2,3,4,8,-11]).Hessian_matrix()
     1586            sage: GS = GenusSymbol_global_ring(A)
     1587            sage: GS.signature_pair_of_matrix()
     1588            (4, 2)
     1589
     1590        """
    5531591        return self._signature
    5541592
     1593
    5551594    def determinant(self):
    556         r, s = self.signature_of_matrix()
     1595        """
     1596        Returns the determinant of this genus, where the determinant
     1597        is the Hessian determinant of the quadratic form whose Gram
     1598        matrix is the Gram matrix giving rise to this global genus
     1599        symbol.
     1600
     1601        INPUT:
     1602            None
     1603
     1604        OUTPUT:
     1605            an integer
     1606
     1607        EXAMPLES:
     1608            sage: from sage.quadratic_forms.genera.genus import GenusSymbol_global_ring
     1609
     1610            sage: A = DiagonalQuadraticForm(ZZ, [1,-2,3,4]).Hessian_matrix()
     1611            sage: GS = GenusSymbol_global_ring(A)
     1612            sage: GS.determinant()
     1613            -384
     1614           
     1615        """
     1616        r, s = self.signature_pair_of_matrix()
    5571617        return (-1)**s*misc.prod([ G.determinant() for G in self._local_symbols ])
  • sage/quadratic_forms/quadratic_form.py

    diff -r 891da50821bd -r af0f19cc490e sage/quadratic_forms/quadratic_form.py
    a b  
    9999        extract_variables, elementary_substitution, add_symmetric    ## Routines to perform elementary variable substitutions.
    100100
    101101    from sage.quadratic_forms.quadratic_form__local_field_invariants \
    102     import rational_diagonal_form, signature, local_diagonal, hasse_invariant, hasse_invariant__OMeara, \
     102    import rational_diagonal_form, signature_vector, signature, local_diagonal, hasse_invariant, hasse_invariant__OMeara, \
    103103        is_hyperbolic, is_anisotropic, is_isotropic, anisotropic_primes, compute_definiteness, \
    104104        is_positive_definite, is_negative_definite, is_indefinite, is_definite    ## Routines to compute p-adic field invariants
    105105
  • sage/quadratic_forms/quadratic_form__genus.py

    diff -r 891da50821bd -r af0f19cc490e sage/quadratic_forms/quadratic_form__genus.py
    a b  
    1 
    21
    32#############################################################
    43##                                                         ##
     
    98from sage.quadratic_forms.genera.genus import Genus, LocalGenusSymbol, \
    109        is_GlobalGenus, is_2_adic_genus, canonical_2_adic_compartments, \
    1110        canonical_2_adic_trains, canonical_2_adic_reduction, \
    12         basis_complement, signature_of_matrix, p_adic_symbol, is_even, \
    13         split_odd,  trace_diag, two_adic_symbol, is_trivial_symbol
     11        basis_complement, p_adic_symbol, is_even_matrix, \
     12        split_odd,  trace_diag_mod_8, two_adic_symbol
     13        #is_trivial_symbol
    1414        #GenusSymbol_p_adic_ring, GenusSymbol_global_ring
     15
     16## Removed signature_pair_of_matrix due to a circular import issue.
     17
    1518## NOTE: Removed the signature routine here... and rewrote it for now.
    1619
    1720
     
    2730    15 of Conway-Sloane), and a signature.
    2831
    2932    EXAMPLES:
     33        sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
     34        sage: Q.global_genus_symbol()
     35        Genus of [2 0 0 0]
     36        [0 4 0 0]
     37        [0 0 6 0]
     38        [0 0 0 8]
     39
     40        sage: Q = QuadraticForm(ZZ, 4, range(10))
     41        sage: Q.global_genus_symbol()
     42        Genus of [ 0  1  2  3]
     43        [ 1  8  5  6]
     44        [ 2  5 14  8]
     45        [ 3  6  8 18]
     46
    3047    """
    3148    ## Check that the form is defined over ZZ
    3249    if not self.base_ring() == IntegerRing():
     
    4259
    4360def local_genus_symbol(self, p):
    4461    """
    45     Returns the Conway-Sloane genus symbol of 2 times a quadratic form defined
    46     over ZZ at a prime number p.
     62    Returns the Conway-Sloane genus symbol of 2 times a quadratic form
     63    defined over ZZ at a prime number p.  This is defined (in the
     64    Genus_Symbol_p_adic_ring() class in the quadratic_forms/genera
     65    subfolder) to be a list of tuples (one for each Jordan component
     66    p^m*A at p, where A is a unimodular symmetric matrix with
     67    coefficients the p-adic integers) of the following form:
     68
     69        1) If p>2 then return triples of the form [m, n, d] where
     70            m = valuation of the component
     71            n = rank of A
     72            d = det(A) in {1,u} for normalized quadratic non-residue u.
     73
     74        2) If p=2 then return quintuples of the form [m, n, s, d, o]
     75        where
     76            m = valuation of the component
     77            n = rank of A
     78            d = det(A) in {1,3,5,7}
     79            s = 0 (or 1) if A is even (or odd)
     80            o = oddity of A (= 0 if s = 0) in Z/8Z
     81              = the trace of the diagonalization of A           
     82
     83    NOTE: The Conway-Sloane convention for describing the prime 'p =
     84    -1' is not supported here, and neither is the convention for
     85    including the 'prime' Infinity.  See note on p370 of Conway-Sloane
     86    (3rd ed) for a discussion of this convention.
    4787
    4888    INPUT:
    4989        p -- a prime number > 0
    5090
    5191    OUTPUT:
    52         Returns a Conway-Sloane genus symbol.
     92        Returns a Conway-Sloane genus symbol at p, which is an
     93        instance of the Genus_Symbol_p_adic_ring class.
    5394
    5495    EXAMPLES:
     96        sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
     97        sage: Q.local_genus_symbol(2)
     98        Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
     99        sage: Q.local_genus_symbol(3)
     100        Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
     101        sage: Q.local_genus_symbol(5)
     102        Genus symbol at 5 : [[0, 4, 1]]
    55103    """
    56104    ## Check that p is prime and that the form is defined over ZZ.
    57105    if not is_prime(p):
     
    74122def CS_genus_symbol_list(self, force_recomputation=False):
    75123    """
    76124    Returns the list of Conway-Sloane genus symbols in increasing order of primes dividing 2*det.
     125
     126    EXAMPLES:
     127        sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
     128        sage: Q.CS_genus_symbol_list()
     129        [Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]],
     130         Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]]
    77131    """   
    78132    ## Try to use the cached list
    79133    if force_recomputation == False:
  • sage/quadratic_forms/quadratic_form__local_field_invariants.py

    diff -r 891da50821bd -r af0f19cc490e sage/quadratic_forms/quadratic_form__local_field_invariants.py
    a b  
    8888    MS = MatrixSpace(Q.base_ring(), n, n)
    8989    T = MS(1)
    9090
    91     ## Construct an integral change of basis matrix T
    92     ## so that T^t * Q * T is diagonal.
     91    ## Clear the entries one row at a time.
     92    for i in range(n):
     93       
     94        ## Deal with rows where the diagonal entry is zero.
     95        if Q[i,i] == 0:
    9396
    94     for i in range(n):
     97            ## Look for a non-zero entry and use it to make the diagonal non-zero (if it exists)
     98            for j in range(i+1, n):
     99                if Q[i,j] != 0:
     100                    temp = MS(1)
     101                    temp[j, i] = 1
     102
     103                    ## Apply the transformation
     104                    Q = Q(temp)
     105                    T = T * temp
     106                    break
     107
     108        ## Create a matrix which deals with off-diagonal entries (all at once for each row)
    95109        temp = MS(1)
    96110        for j in range(i+1, n):
    97             temp[j,j] = 1
    98             temp[i,j] = -Q[i,j] / ZZ(2) * Q[i,i]
     111            temp[i,j] = -Q[i,j] / (Q[i,i] * 2)
    99112
    100113        Q = Q(temp)
    101         T = temp * T
     114        T = T * temp
     115
    102116
    103117    ## Return the appropriate output
    104118    if return_matrix:
     
    107121        return Q
    108122
    109123
     124
     125
     126
     127def signature_vector(self):
     128    """
     129    Returns the triple (p, n, z) of integers where
     130        p = number of positive eigenvalues
     131        n = number of negative eigenvalues
     132        z = number of zero eigenvalues
     133    for the symmetric matrix associated to Q.
     134
     135    INPUT:
     136        None
     137
     138    OUTPUT:
     139        a triple of integers
     140
     141    EXAMPLES:
     142   
     143    """
     144    diag = self.rational_diagonal_form()
     145    p = 0
     146    n = 0
     147    z = 0
     148    for i in range(diag.dim()):
     149        if diag[i,i] > 0:
     150            p += 1
     151        elif diag[i,i] < 0:
     152            n += 1
     153        else:
     154            z += 1
     155
     156    ## TO DO: Cache this result?
     157
     158    return (p, n, z)
     159
     160
     161
    110162def signature(self):
    111163    """
    112164    Returns the signature of the quadratic form, defined as:
     
    121173    EXAMPLES:
    122174   
    123175    """
    124     diag = self.rational_diagonal_form()
    125     return sum([sgn(diag[i,i])  for i in range(diag.dim())])
     176    (p, n, z) = self.signature_vector()
     177    return p - n
     178
     179
    126180
    127181
    128182