diff options
| -rw-r--r-- | kummer_degree.sage | 53 | ||||
| -rw-r--r-- | todo-list | 7 |
2 files changed, 36 insertions, 24 deletions
diff --git a/kummer_degree.sage b/kummer_degree.sage index 2b03716..59c0929 100644 --- a/kummer_degree.sage +++ b/kummer_degree.sage | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | # set of generators is sufficient. # | 9 | # set of generators is sufficient. # |
| 10 | ############################################################################# | 10 | ############################################################################# |
| 11 | 11 | ||
| 12 | from sage.misc.cachefunc import CachedFunction | ||
| 13 | |||
| 12 | # Computes the "adelic Kummer failure", i.e. the degrees of the intersection | 14 | # Computes the "adelic Kummer failure", i.e. the degrees of the intersection |
| 13 | # of the the Kummer extension Q(\sqrt{2^n}{G}) with the M-th cyclotomic field | 15 | # of the the Kummer extension Q(\sqrt{2^n}{G}) with the M-th cyclotomic field |
| 14 | # over Q_{2^n}. | 16 | # over Q_{2^n}. |
| @@ -218,11 +220,11 @@ def bad_primes( B ): | |||
| 218 | return | 220 | return |
| 219 | 221 | ||
| 220 | # Compute which primes l divide all minors of the exponent matrix | 222 | # Compute which primes l divide all minors of the exponent matrix |
| 221 | bad_primes = list( prime_factors( gcd( M.minors(a) ) ) ) | 223 | bad_p = list( prime_factors( gcd( M.minors(a) ) ) ) |
| 222 | if 2 not in bad_primes: | 224 | if 2 not in bad_p: |
| 223 | bad_primes += [2] # 2 is always bad | 225 | bad_p += [2] # 2 is always bad |
| 224 | 226 | ||
| 225 | return sorted(bad_primes) # Ensures 2 is always first | 227 | return sorted(bad_p) # Ensures 2 is always first |
| 226 | 228 | ||
| 227 | # Computes the l-adic failure for a specific l. Returns a "table" as | 229 | # Computes the l-adic failure for a specific l. Returns a "table" as |
| 228 | # described above "total_l_adic_failure". | 230 | # described above "total_l_adic_failure". |
| @@ -345,11 +347,12 @@ def compute_vl( p, n, m, r ): | |||
| 345 | 347 | ||
| 346 | return M - m + r*n - sum( ni ) | 348 | return M - m + r*n - sum( ni ) |
| 347 | 349 | ||
| 348 | # Computes a basis for G from a set of generators. | 350 | # Computes a basis for G from a frozen_set of generators. |
| 349 | # Returns a pair (B,torsion) where B is a list of rational numbers and | 351 | # Returns a pair (B,torsion) where B is a list of rational numbers and |
| 350 | # torsion is true if -1 is in G and false otherwise. | 352 | # torsion is true if -1 is in G and false otherwise. |
| 353 | @CachedFunction | ||
| 351 | def generators_to_basis( G ): | 354 | def generators_to_basis( G ): |
| 352 | (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) | 355 | (BM,BM_primes) = exponent_matrix_with_sign_and_primes( list(G) ) |
| 353 | BM = BM.echelon_form() | 356 | BM = BM.echelon_form() |
| 354 | BM_primes.append(-1) | 357 | BM_primes.append(-1) |
| 355 | 358 | ||
| @@ -416,6 +419,7 @@ def adjust_sign( B ): | |||
| 416 | # Given the exponent matrix M of a list of rational numbers B, returns the | 419 | # Given the exponent matrix M of a list of rational numbers B, returns the |
| 417 | # coefficients of a linear combination that is weakly l-divisible, or [] if | 420 | # coefficients of a linear combination that is weakly l-divisible, or [] if |
| 418 | # the B[i] are strongly l-independent. | 421 | # the B[i] are strongly l-independent. |
| 422 | @CachedFunction | ||
| 419 | def find_combination( M, l ): | 423 | def find_combination( M, l ): |
| 420 | M = M.change_ring( GF( l ) ) | 424 | M = M.change_ring( GF( l ) ) |
| 421 | if M.rank() != min( M.dimensions() ): | 425 | if M.rank() != min( M.dimensions() ): |
| @@ -469,10 +473,11 @@ def exponent_matrix_with_sign_and_primes( B ): | |||
| 469 | rows.append( rowg ) | 473 | rows.append( rowg ) |
| 470 | return ( matrix( rows ), prime_list ) | 474 | return ( matrix( rows ), prime_list ) |
| 471 | 475 | ||
| 472 | # This is a wrapper function for total_kummer_failure( G, True ), see below. | 476 | # The function TotalKummerFailure (with its many wrapper functions) computes |
| 473 | def TotalKummerFailure( G ): | 477 | # the total table of Kummer Failures for the given group G. Moreover, the |
| 474 | total_kummer_failure( G, True ) | 478 | # result is cached for speeding up following computations on the same group, |
| 475 | 479 | # even if the same group is given with a different set of generators. | |
| 480 | # | ||
| 476 | # Input: any set of generators for a subgroup G of Q*. | 481 | # Input: any set of generators for a subgroup G of Q*. |
| 477 | # If output=False, returns a 4-uple (t,MM,NN,D): | 482 | # If output=False, returns a 4-uple (t,MM,NN,D): |
| 478 | # - t is a pair, where t[0] is the rank of G and t[1] is either True (if G | 483 | # - t is a pair, where t[0] is the rank of G and t[1] is either True (if G |
| @@ -485,9 +490,18 @@ def TotalKummerFailure( G ): | |||
| 485 | # computed for a torsion-free part of G. | 490 | # computed for a torsion-free part of G. |
| 486 | # If output is True, outputs this data in a human-readable way and does not | 491 | # If output is True, outputs this data in a human-readable way and does not |
| 487 | # return any value. | 492 | # return any value. |
| 488 | def total_kummer_failure( G, output ): | ||
| 489 | 493 | ||
| 494 | def TotalKummerFailure( G ): | ||
| 495 | total_kummer_failure( G, True ) | ||
| 496 | |||
| 497 | @CachedFunction | ||
| 498 | def total_kummer_failure_cachable( G ): | ||
| 490 | B, torsion = generators_to_basis( G ) | 499 | B, torsion = generators_to_basis( G ) |
| 500 | return total_kummer_failure_cachable_basis( tuple(B), torsion ) | ||
| 501 | |||
| 502 | @CachedFunction | ||
| 503 | def total_kummer_failure_cachable_basis( B, torsion ): | ||
| 504 | B = list(B) | ||
| 491 | r = len(B) # Rank of G | 505 | r = len(B) # Rank of G |
| 492 | 506 | ||
| 493 | if r == 0: | 507 | if r == 0: |
| @@ -495,15 +509,15 @@ def total_kummer_failure( G, output ): | |||
| 495 | return False | 509 | return False |
| 496 | 510 | ||
| 497 | # Compute l-adic data (straightforward) | 511 | # Compute l-adic data (straightforward) |
| 498 | ( bad_primes, l_adic_failure_table ) = total_l_adic_failure( B ) | 512 | ( bad_p, l_adic_failure_table ) = total_l_adic_failure( B ) |
| 499 | 513 | ||
| 500 | # Compute adelic data. | 514 | # Compute adelic data. |
| 501 | (GB,d) = adjust_sign( make_good_basis( B, 2 ) ) | 515 | (GB,d) = adjust_sign( make_good_basis( B, 2 ) ) |
| 502 | adelic_failure_table = adelic_failure_gb( GB, d ) | 516 | adelic_failure_table = adelic_failure_gb( GB, d ) |
| 503 | 517 | ||
| 504 | # Computing the bounds M0 and N0 | 518 | # Computing the bounds M0 and N0 |
| 505 | N0 = prod( [ bad_primes[i] ^ len( l_adic_failure_table[i][-1][0] ) \ | 519 | N0 = prod( [ bad_p[i] ^ len( l_adic_failure_table[i][-1][0] ) \ |
| 506 | for i in range(len(bad_primes)) ] ) | 520 | for i in range(len(bad_p)) ] ) |
| 507 | # Extra factors of 2 may come from the adelic failure | 521 | # Extra factors of 2 may come from the adelic failure |
| 508 | N0 = lcm( N0, 2^len( adelic_failure_table ) ) | 522 | N0 = lcm( N0, 2^len( adelic_failure_table ) ) |
| 509 | divs_N0 = divisors(N0) | 523 | divs_N0 = divisors(N0) |
| @@ -530,16 +544,20 @@ def total_kummer_failure( G, output ): | |||
| 530 | FT[j][l] = lcm( FT[j][l], pp[1] ) | 544 | FT[j][l] = lcm( FT[j][l], pp[1] ) |
| 531 | 545 | ||
| 532 | # Adding l-adic failure to the table | 546 | # Adding l-adic failure to the table |
| 533 | for i in range( len( bad_primes ) ): | 547 | for i in range( len( bad_p ) ): |
| 534 | l = bad_primes[i] | 548 | l = bad_p[i] |
| 535 | for j in range(len(divs_N0)): | 549 | for j in range(len(divs_N0)): |
| 536 | dN = divs_N0[j] | 550 | dN = divs_N0[j] |
| 537 | fl = l_adic_failure_from_data(B,l,l_adic_failure_table[i],dN,dN) | 551 | fl = l_adic_failure_from_data(B,l,l_adic_failure_table[i],dN,dN) |
| 538 | for h in range(len(divs_M0)): | 552 | for h in range(len(divs_M0)): |
| 539 | FT[j][h] *= fl | 553 | FT[j][h] *= fl |
| 540 | 554 | ||
| 541 | ret = ( ( r, torsion ), ( M0, divs_M0 ), ( N0, divs_N0 ), FT ) | 555 | return ( ( r, torsion ), ( M0, divs_M0 ), ( N0, divs_N0 ), FT ) |
| 542 | 556 | ||
| 557 | def total_kummer_failure( G, output ): | ||
| 558 | |||
| 559 | ret = total_kummer_failure_cachable( frozenset(G) ) | ||
| 560 | |||
| 543 | if output: | 561 | if output: |
| 544 | print_total_table( ret ) | 562 | print_total_table( ret ) |
| 545 | # Uncomment following line for case list description. | 563 | # Uncomment following line for case list description. |
| @@ -728,3 +746,4 @@ def KummerDegree( G, M, N ): | |||
| 728 | failure = FT | 746 | failure = FT |
| 729 | 747 | ||
| 730 | return e_deg/failure[divs_N0.index(gcd(N,N0))][divs_M0.index(gcd(M,M0))] | 748 | return e_deg/failure[divs_N0.index(gcd(N,N0))][divs_M0.index(gcd(M,M0))] |
| 749 | |||
diff --git a/todo-list b/todo-list deleted file mode 100644 index eb52de1..0000000 --- a/todo-list +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | - Decent output format. What information might the user want? | ||
| 2 | - maybe not so bad right now | ||
| 3 | - Caching for efficient subsequent computations on the same group | ||
| 4 | - What is Sage standard for this kind of stuff? | ||
| 5 | - Standardize to Sage coding style | ||
| 6 | - Should the given degree be over Q or over the cyclotomic field? | ||
| 7 | - I don't even remember what I am doing now on top of my mind... | ||
