aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano.tronto@gmail.com>2019-07-31 14:32:49 +0200
committerSebastiano Tronto <sebastiano.tronto@gmail.com>2019-07-31 14:32:49 +0200
commit53025b2c837bc492d23b316b1a1003e13816903c (patch)
tree88393f6a061c27099be68faef3c6f26b03245297
parentcc355fbe7e53052630ed33b06c19d17b1d54cb5c (diff)
downloadkummer-degrees-53025b2c837bc492d23b316b1a1003e13816903c.tar.gz
kummer-degrees-53025b2c837bc492d23b316b1a1003e13816903c.zip
Just some refactoring
Diffstat (limited to '')
-rw-r--r--kummer_degree.sage195
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]
188def total_l_adic_failure( B ): 188def 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.
200def bad_primes( B ): 200def 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).
280def parameters_Q( gb, l ): 275def 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).
370def make_good_basis( b, l ): 373def 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.
474def exponent_matrix_with_sign_and_primes( B ): 482def 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 ):
510def total_kummer_failure( G, output ): 518def 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 ):
689def print_case_list( data ): 684def 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.
731def kummer_failure_from_total_table( M, N, data ): 715def 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))]

Generated with cgit - Back to sebastiano.tronto.net