diff options
| author | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2019-07-31 14:32:49 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2019-07-31 14:32:49 +0200 |
| commit | 53025b2c837bc492d23b316b1a1003e13816903c (patch) | |
| tree | 88393f6a061c27099be68faef3c6f26b03245297 | |
| parent | cc355fbe7e53052630ed33b06c19d17b1d54cb5c (diff) | |
| download | kummer-degrees-53025b2c837bc492d23b316b1a1003e13816903c.tar.gz kummer-degrees-53025b2c837bc492d23b316b1a1003e13816903c.zip | |
Just some refactoring
| -rw-r--r-- | kummer_degree.sage | 195 |
1 files changed, 88 insertions, 107 deletions
diff --git a/kummer_degree.sage b/kummer_degree.sage index f592461..6a1ac2a 100644 --- a/kummer_degree.sage +++ b/kummer_degree.sage | |||
| @@ -187,7 +187,7 @@ def special_embed( (n,b) ): | |||
| 187 | # degree of Q_{l^m,l^n} over Q_{l^m}, where l = L[i] | 187 | # degree of Q_{l^m,l^n} over Q_{l^m}, where l = L[i] |
| 188 | def total_l_adic_failure( B ): | 188 | def total_l_adic_failure( B ): |
| 189 | 189 | ||
| 190 | bp = bad_primes( B ) | 190 | bp = bad_primes(B) |
| 191 | ret = ( bp, [] ) | 191 | ret = ( bp, [] ) |
| 192 | 192 | ||
| 193 | for l in bp: | 193 | for l in bp: |
| @@ -196,25 +196,21 @@ def total_l_adic_failure( B ): | |||
| 196 | return ret | 196 | return ret |
| 197 | 197 | ||
| 198 | # Computes the "bad primes", i.e. the ones for which the l-adic part is not | 198 | # Computes the "bad primes", i.e. the ones for which the l-adic part is not |
| 199 | # maximal. Used by l_adic_degree and total_l_adic_failure. | 199 | # maximal. Used by total_l_adic_failure. |
| 200 | def bad_primes( B ): | 200 | def bad_primes( B ): |
| 201 | M = exponent_matrix( B ) | 201 | M = exponent_matrix( B ) |
| 202 | (a,b) = M.dimensions() | 202 | (a,b) = M.dimensions() |
| 203 | |||
| 203 | if a > b or M.rank() < a: | 204 | if a > b or M.rank() < a: |
| 204 | print "This is not a basis" | 205 | print "This is not a basis" |
| 205 | return | 206 | return |
| 206 | 207 | ||
| 207 | # Compute which primes l divide all minors of the exponent matrix | 208 | # Compute which primes l divide all minors of the exponent matrix |
| 208 | ms = M.minors( a ) | 209 | bad_primes = list( prime_factors( gcd( M.minors(a) ) ) ) |
| 209 | d = ms[0] | ||
| 210 | for m in ms: | ||
| 211 | d = gcd( d, m ) | ||
| 212 | bad_primes = list( prime_factors( d ) ) | ||
| 213 | if 2 not in bad_primes: | 210 | if 2 not in bad_primes: |
| 214 | bad_primes += [2] # 2 is always bad | 211 | bad_primes += [2] # 2 is always bad |
| 215 | bad_primes.sort() # Ensures 2 is always first | ||
| 216 | 212 | ||
| 217 | return bad_primes | 213 | return sorted(bad_primes) # Ensures 2 is always first |
| 218 | 214 | ||
| 219 | # Computes the l-adic failure for a specific l. Returns a "table" as described | 215 | # Computes the l-adic failure for a specific l. Returns a "table" as described |
| 220 | # above "total_l_adic_failure". | 216 | # above "total_l_adic_failure". |
| @@ -266,7 +262,6 @@ def l_adic_failure_from_data( B, l, tablel, M, N ): | |||
| 266 | return 1 | 262 | return 1 |
| 267 | r = len(B) | 263 | r = len(B) |
| 268 | 264 | ||
| 269 | # Basically, the "dual" of what we do in l_adic_degree. | ||
| 270 | if m > len(tablel): | 265 | if m > len(tablel): |
| 271 | if n > len(tablel): | 266 | if n > len(tablel): |
| 272 | return l^tablel[-1][1] | 267 | return l^tablel[-1][1] |
| @@ -278,11 +273,12 @@ def l_adic_failure_from_data( B, l, tablel, M, N ): | |||
| 278 | # Returns the l-dvisibility parameters of G over Q, given a good basis gb of G, | 273 | # Returns the l-dvisibility parameters of G over Q, given a good basis gb of G, |
| 279 | # as a list of pairs (di,hi). | 274 | # as a list of pairs (di,hi). |
| 280 | def parameters_Q( gb, l ): | 275 | def parameters_Q( gb, l ): |
| 281 | ret = [] | 276 | #ret = [] |
| 282 | for i in range( len( gb ) ): | 277 | #for i in range( len( gb ) ): |
| 283 | for j in gb[i]: | 278 | # for j in gb[i]: |
| 284 | ret.append( (i,0) ) | 279 | # ret.append( (i,0) ) |
| 285 | return ret | 280 | #return ret |
| 281 | return [x for a in [[(i,0)]*len(gb[i]) for i in range(len(gb))] for x in a] | ||
| 286 | 282 | ||
| 287 | # Computes the l-divisibility parameters of G over Q4, given a good basis gb | 283 | # Computes the l-divisibility parameters of G over Q4, given a good basis gb |
| 288 | # over Q for G. Returns a list of pairs (di,hi). | 284 | # over Q for G. Returns a list of pairs (di,hi). |
| @@ -293,9 +289,10 @@ def parameters_Q4( gb, l ): | |||
| 293 | return parameters_Q( gb, l ) | 289 | return parameters_Q( gb, l ) |
| 294 | else: | 290 | else: |
| 295 | # Converts from "good basis format" to simple list | 291 | # Converts from "good basis format" to simple list |
| 296 | b = [] | 292 | #b = [] |
| 297 | for x in gb: | 293 | #for x in gb: |
| 298 | b += x | 294 | # b += x |
| 295 | b = [ x for a in gb for x in a ] | ||
| 299 | 296 | ||
| 300 | M = exponent_matrix( b ) | 297 | M = exponent_matrix( b ) |
| 301 | 298 | ||
| @@ -314,7 +311,7 @@ def parameters_Q4( gb, l ): | |||
| 314 | # Basis elements that actually appear in the combination | 311 | # Basis elements that actually appear in the combination |
| 315 | c = [ b[i] for i in range(len(a[0:-1])) if a[i] != 0 ] | 312 | c = [ b[i] for i in range(len(a[0:-1])) if a[i] != 0 ] |
| 316 | 313 | ||
| 317 | # Return the parameters, changing only the ones fo the element | 314 | # Return the parameters, changing only the ones for the element |
| 318 | # of highest divisibility that appears in the combination. | 315 | # of highest divisibility that appears in the combination. |
| 319 | ret = [] | 316 | ret = [] |
| 320 | div_max = -1 | 317 | div_max = -1 |
| @@ -350,31 +347,39 @@ def generators_to_basis( G ): | |||
| 350 | (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) | 347 | (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) |
| 351 | BM = BM.echelon_form() | 348 | BM = BM.echelon_form() |
| 352 | BM_primes.append(-1) | 349 | BM_primes.append(-1) |
| 353 | B = [] | ||
| 354 | torsion = False | ||
| 355 | 350 | ||
| 356 | for r in BM.rows(): | 351 | #B = [] |
| 357 | gr = product( [ BM_primes[i]^r[i] for i in range(len(r)) ] ) | 352 | #torsion = False |
| 358 | if gr == -1: | 353 | |
| 359 | torsion = True | 354 | #for r in BM.rows(): |
| 360 | break | 355 | # gr = product( [ BM_primes[i]^r[i] for i in range(len(r)) ] ) |
| 361 | elif gr == 1: | 356 | # if gr == -1: |
| 362 | break | 357 | # torsion = True |
| 363 | else: | 358 | # break |
| 364 | B.append(gr) | 359 | # elif gr == 1: |
| 360 | # break | ||
| 361 | # else: | ||
| 362 | # B.append(gr) | ||
| 363 | |||
| 364 | #return (B,torsion) | ||
| 365 | |||
| 366 | B = [ prod([BM_primes[i]^r[i] for i in range(len(r))]) for r in BM.rows() ] | ||
| 367 | |||
| 368 | return ( [ x for x in B if abs(x) != 1 ], -1 in B ) | ||
| 365 | 369 | ||
| 366 | return (B,torsion) | ||
| 367 | 370 | ||
| 368 | # Given any basis b of a group G computes an l-good basis for G. This is done | 371 | # Given any basis b of a group G computes an l-good basis for G. This is done |
| 369 | # using the algorithm outlined in the proof of Theorem 14 of (Debry-Perucca). | 372 | # using the algorithm outlined in the proof of Theorem 14 of (Debry-Perucca). |
| 370 | def make_good_basis( b, l ): | 373 | def make_good_basis( b, l ): |
| 371 | M = exponent_matrix( b ) | 374 | M = exponent_matrix( b ) |
| 372 | d = [] | 375 | #d = [] |
| 373 | B = [] | 376 | #B = [] |
| 374 | for i in range(len(b)): | 377 | #for i in range(len(b)): |
| 375 | di = divisibility( M[i], l ) | 378 | # di = divisibility( M[i], l ) |
| 376 | d.append( di ) | 379 | # d.append( di ) |
| 377 | B.append( abs(b[i])^(1/(l^di)) ) | 380 | # B.append( abs(b[i])^(1/(l^di)) ) |
| 381 | d = [ divisibility(x,l) for x in M ] | ||
| 382 | B = [ abs(b[i])^(1/(l^d[i])) for i in range(len(b)) ] | ||
| 378 | 383 | ||
| 379 | # Computes the coeffiecients of a linear combination of the rows of M | 384 | # Computes the coeffiecients of a linear combination of the rows of M |
| 380 | # that is zero modulo l. These coefficients are elements of F_l. | 385 | # that is zero modulo l. These coefficients are elements of F_l. |
| @@ -393,23 +398,26 @@ def make_good_basis( b, l ): | |||
| 393 | 398 | ||
| 394 | x = [ (a/coeffs[maxi]).lift() for a in coeffs ] # Now a vector of ints | 399 | x = [ (a/coeffs[maxi]).lift() for a in coeffs ] # Now a vector of ints |
| 395 | 400 | ||
| 396 | new_element = 1 | 401 | #new_elt = 1 |
| 397 | for i in range(len(d)): | 402 | #for i in range(len(d)): |
| 398 | new_element *= b[i]^( x[i] * l^(d[maxi]-d[i]) ) | 403 | # new_elt *= b[i]^( x[i] * l^(d[maxi]-d[i]) ) |
| 404 | new_elt = prod([ b[i]^(x[i]*l^(d[maxi]-d[i])) for i in range(len(d)) ]) | ||
| 399 | 405 | ||
| 400 | b[maxi] = new_element | 406 | b[maxi] = new_elt |
| 401 | M = exponent_matrix( b ) | 407 | M = exponent_matrix( b ) |
| 402 | d[maxi] = divisibility( M[maxi], l ) | 408 | d[maxi] = divisibility( M[maxi], l ) |
| 403 | B[maxi] = abs(b[maxi])^(1/(l^d[maxi])) | 409 | B[maxi] = abs(b[maxi])^(1/(l^d[maxi])) |
| 404 | 410 | ||
| 405 | coeffs = find_combination( exponent_matrix( B ), l ) | 411 | coeffs = find_combination( exponent_matrix( B ), l ) |
| 406 | 412 | ||
| 407 | GB = [[]] | 413 | #GB = [[]] |
| 408 | for i in range(len(d)): | 414 | #for i in range(len(d)): |
| 409 | while( len(GB) <= d[i] ): | 415 | # while( len(GB) <= d[i] ): |
| 410 | GB.append([]) | 416 | # GB.append([]) |
| 411 | GB[d[i]].append(b[i]) | 417 | # GB[d[i]].append(b[i]) |
| 412 | return GB | 418 | #return GB |
| 419 | |||
| 420 | return [[b[i] for i in range(len(b)) if d[i]==j] for j in range(max(d)+1)] | ||
| 413 | 421 | ||
| 414 | # Takes a good basis B and adjusts the sign of the elements so that there is at | 422 | # Takes a good basis B and adjusts the sign of the elements so that there is at |
| 415 | # most one negative generator (of positive divisibility). The input is a good | 423 | # most one negative generator (of positive divisibility). The input is a good |
| @@ -472,11 +480,14 @@ def exponent_matrix( B ): | |||
| 472 | # Returns a pair (M,L) where M is the modified exponent matrix and L is the | 480 | # Returns a pair (M,L) where M is the modified exponent matrix and L is the |
| 473 | # list of primes appearing in the factorization. | 481 | # list of primes appearing in the factorization. |
| 474 | def exponent_matrix_with_sign_and_primes( B ): | 482 | def exponent_matrix_with_sign_and_primes( B ): |
| 475 | prime_list = set() | 483 | #prime_list = set() |
| 476 | for g in B: | 484 | #for g in B: |
| 477 | prime_list |= set( prime_factors( g ) ) | 485 | # prime_list |= set( prime_factors( g ) ) |
| 478 | prime_list = list( prime_list ) | 486 | #prime_list = list( prime_list ) |
| 487 | |||
| 488 | prime_list = list({ x for a in [prime_factors(g) for g in B] for x in a }) | ||
| 479 | np = len( prime_list ) | 489 | np = len( prime_list ) |
| 490 | |||
| 480 | rows = [] | 491 | rows = [] |
| 481 | for g in B: | 492 | for g in B: |
| 482 | rowg = [0] * np | 493 | rowg = [0] * np |
| @@ -484,10 +495,7 @@ def exponent_matrix_with_sign_and_primes( B ): | |||
| 484 | for i in range( np ): | 495 | for i in range( np ): |
| 485 | if f[0] == prime_list[i]: | 496 | if f[0] == prime_list[i]: |
| 486 | rowg[i] = f[1] | 497 | rowg[i] = f[1] |
| 487 | s = 0 | 498 | rowg.append( 1 - max(0,sgn(g)) ) |
| 488 | if sgn(g) == -1: | ||
| 489 | s = 1 | ||
| 490 | rowg.append( s ) | ||
| 491 | rows.append( rowg ) | 499 | rows.append( rowg ) |
| 492 | return ( matrix( rows ), prime_list ) | 500 | return ( matrix( rows ), prime_list ) |
| 493 | 501 | ||
| @@ -510,13 +518,12 @@ def TotalKummerFailure( G ): | |||
| 510 | def total_kummer_failure( G, output ): | 518 | def total_kummer_failure( G, output ): |
| 511 | 519 | ||
| 512 | B, torsion = generators_to_basis( G ) | 520 | B, torsion = generators_to_basis( G ) |
| 521 | r = len(B) # Rank of G | ||
| 513 | 522 | ||
| 514 | if len(B) == 0: | 523 | if r == 0: |
| 515 | print "G is torsion. The extension is cyclotomic. Stopping." | 524 | print "G is torsion. The extension is cyclotomic. Stopping." |
| 516 | return False | 525 | return False |
| 517 | 526 | ||
| 518 | r = len(B) # Rank of G | ||
| 519 | |||
| 520 | # Compute l-adic data (straightforward) | 527 | # Compute l-adic data (straightforward) |
| 521 | ( bad_primes, l_adic_failure_table ) = total_l_adic_failure( B ) | 528 | ( bad_primes, l_adic_failure_table ) = total_l_adic_failure( B ) |
| 522 | 529 | ||
| @@ -525,9 +532,11 @@ def total_kummer_failure( G, output ): | |||
| 525 | adelic_failure_table = adelic_failure_gb( GB, d ) | 532 | adelic_failure_table = adelic_failure_gb( GB, d ) |
| 526 | 533 | ||
| 527 | # Computing the bounds M0 and N0 | 534 | # Computing the bounds M0 and N0 |
| 528 | N0 = 1 | 535 | #N0 = 1 |
| 529 | for i in range(len( bad_primes )): | 536 | #for i in range(len( bad_primes )): |
| 530 | N0 *= bad_primes[i] ^ len( l_adic_failure_table[i][-1][0] ) | 537 | # N0 *= bad_primes[i] ^ len( l_adic_failure_table[i][-1][0] ) |
| 538 | N0 = prod( [ bad_primes[i] ^ len( l_adic_failure_table[i][-1][0] ) \ | ||
| 539 | for i in range(len(bad_primes)) ] ) | ||
| 531 | # Extra factors of 2 may come from the adelic failure | 540 | # Extra factors of 2 may come from the adelic failure |
| 532 | N0 = lcm( N0, 2^len( adelic_failure_table ) ) | 541 | N0 = lcm( N0, 2^len( adelic_failure_table ) ) |
| 533 | divs_N0 = divisors(N0) | 542 | divs_N0 = divisors(N0) |
| @@ -638,20 +647,6 @@ def print_total_table( data ): | |||
| 638 | print "gcd(N,N0) and the column labelled with gcd(M,M0)." | 647 | print "gcd(N,N0) and the column labelled with gcd(M,M0)." |
| 639 | print "" | 648 | print "" |
| 640 | 649 | ||
| 641 | #print "Columns correspond to values of M, rows to values of N." | ||
| 642 | #print "" | ||
| 643 | #print "The degree of the Kummer extension (M,N) can be extracted by taking" | ||
| 644 | #print "the value f (failure) of the entry at (gcd(N,N0),gcd(M,M0)) and" | ||
| 645 | #print "simply computing ed(M,N) / f, where ed(M,N) is the expected degree" | ||
| 646 | #print "of the Kummer extension." | ||
| 647 | #if torsion: | ||
| 648 | # print "In this case (-1 is in G), we have ed(M,N) = 2^e*phi(M)*N^r," | ||
| 649 | # print "where e=1 if N is even and e=0 if N is odd." | ||
| 650 | #else: | ||
| 651 | # print "In this case (G is torsion-free) we have ed(M,N) = phi(M)*N^r," | ||
| 652 | #print "where r is the rank of G." | ||
| 653 | #print "" | ||
| 654 | |||
| 655 | if torsion: | 650 | if torsion: |
| 656 | FT1 = torsion_table_even( data ) | 651 | FT1 = torsion_table_even( data ) |
| 657 | else: | 652 | else: |
| @@ -689,57 +684,46 @@ def print_total_table( data ): | |||
| 689 | def print_case_list( data ): | 684 | def print_case_list( data ): |
| 690 | 685 | ||
| 691 | ( ( r, torsion ), ( M0, divs_M0 ), ( N0, divs_N0 ), FT ) = data | 686 | ( ( r, torsion ), ( M0, divs_M0 ), ( N0, divs_N0 ), FT ) = data |
| 692 | |||
| 693 | FT_odd = torsion_table_odd( data ) | 687 | FT_odd = torsion_table_odd( data ) |
| 694 | # FT1 is either FT or FT_even in the torsion case | 688 | |
| 695 | FT1 = FT | ||
| 696 | if torsion: | 689 | if torsion: |
| 697 | FT1 = torsion_table_even( data ) | 690 | FT1 = torsion_table_even( data ) |
| 698 | pf = [] | 691 | pf = sorted(list({ x for row in FT_odd for x in row })) |
| 699 | for row in FT1: | 692 | else: |
| 700 | pf += row | 693 | FT1 = FT |
| 701 | if torsion: | 694 | pf = sorted(list({ x for row in FT1 for x in row })) |
| 702 | for row in FT_odd: | 695 | |
| 703 | pf += row | ||
| 704 | pf = list(set(pf)) | ||
| 705 | pf.sort() | ||
| 706 | for f in pf: | 696 | for f in pf: |
| 707 | print "Failure is", f, "if", | 697 | print "Failure is", f, "if", |
| 708 | if torsion: | 698 | if torsion: |
| 709 | print "M/N is EVEN and", | 699 | print "M/N is EVEN and", |
| 710 | print "(gcd(M,M0),gcd(N,N0)) is one of the following:" | 700 | print "(gcd(M,M0),gcd(N,N0)) is one of the following:" |
| 711 | lijst = [] | 701 | print [ (divs_M0[j], divs_N0[i]) \ |
| 712 | for i in range(len(divs_N0)): | 702 | for i in range(len(divs_N0)) for j in range(len(divs_M0)) \ |
| 713 | for j in range(len(divs_M0)): | 703 | if FT1[i][j] == f ] |
| 714 | if FT1[i][j] == f: | 704 | |
| 715 | lijst.append( ( divs_M0[j], divs_N0[i] ) ) | ||
| 716 | print lijst | ||
| 717 | if torsion: | 705 | if torsion: |
| 718 | print "or if M/N is ODD and (gcd(M,M0)),gcd(N,N0)) is one of the", | 706 | print "or if M/N is ODD and (gcd(M,M0)),gcd(N,N0)) is one of the", |
| 719 | print "following:" | 707 | print "following:" |
| 720 | 708 | print [ (divs_M0[j], divs_N0[i]) \ | |
| 721 | lijst_odd = [] | 709 | for i in range(len(divs_N0)) for j in range(len(divs_M0)) \ |
| 722 | for i in range(len(divs_N0)): | 710 | if FT_odd[i][j] == f ] |
| 723 | for j in range(len(divs_M0)): | ||
| 724 | if FT_odd[i][j] == f: | ||
| 725 | lijst_odd.append( ( divs_M0[j], divs_N0[i] ) ) | ||
| 726 | print lijst_odd | ||
| 727 | 711 | ||
| 728 | print "" | 712 | print "" |
| 729 | 713 | ||
| 730 | # Extracts a specific value of failure from the total table. | 714 | # Extracts a specific value of failure from the total table. |
| 731 | def kummer_failure_from_total_table( M, N, data ): | 715 | def kummer_failure_from_total_table( M, N, data ): |
| 732 | ( ( r, torsion ), ( M0, divs_M0 ), ( N0, divs_N0 ), FT ) = data | 716 | ( ( r, torsion ), ( M0, divs_M0 ), ( N0, divs_N0 ), FT ) = data |
| 733 | FT1 = FT | 717 | |
| 734 | if torsion: | 718 | if torsion: |
| 735 | if (M/N) % 2 == 0: | 719 | if (M/N) % 2 == 0: |
| 736 | FT1 = torsion_table_even( data ) | 720 | FT1 = torsion_table_even( data ) |
| 737 | else: | 721 | else: |
| 738 | FT1 = torsion_table_odd( data ) | 722 | FT1 = torsion_table_odd( data ) |
| 723 | else: | ||
| 724 | FT1 = FT | ||
| 739 | 725 | ||
| 740 | i = divs_N0.index( gcd( N, N0 ) ) | 726 | return FT1[divs_N0.index( gcd( N, N0 ) )][divs_M0.index( gcd( M, M0 ) )] |
| 741 | j = divs_M0.index( gcd( M, M0 ) ) | ||
| 742 | return FT1[i][j] | ||
| 743 | 727 | ||
| 744 | # Computes the degree of the Kummer extension (M,N), by taking as input the | 728 | # Computes the degree of the Kummer extension (M,N), by taking as input the |
| 745 | # table computed by TotalKummerFailure. | 729 | # table computed by TotalKummerFailure. |
| @@ -768,9 +752,6 @@ def KummerDegree( G, M, N ): | |||
| 768 | if torsion and N % 2 == 0: | 752 | if torsion and N % 2 == 0: |
| 769 | exp_deg *= 2 | 753 | exp_deg *= 2 |
| 770 | 754 | ||
| 771 | j = divs_M0.index(gcd(M,M0)) | ||
| 772 | i = divs_N0.index(gcd(N,N0)) | ||
| 773 | |||
| 774 | if torsion: | 755 | if torsion: |
| 775 | if (M/N)%2 == 0: | 756 | if (M/N)%2 == 0: |
| 776 | failure = torsion_table_even( data ) | 757 | failure = torsion_table_even( data ) |
| @@ -779,4 +760,4 @@ def KummerDegree( G, M, N ): | |||
| 779 | else: | 760 | else: |
| 780 | failure = FT | 761 | failure = FT |
| 781 | 762 | ||
| 782 | return exp_deg / failure[i][j] | 763 | return exp_deg/failure[divs_N0.index(gcd(N,N0))][divs_M0.index(gcd(M,M0))] |
