diff options
Diffstat (limited to '')
| -rw-r--r-- | kummer_degree.sage | 195 |
1 files changed, 71 insertions, 124 deletions
diff --git a/kummer_degree.sage b/kummer_degree.sage index 5800559..6f3dab9 100644 --- a/kummer_degree.sage +++ b/kummer_degree.sage | |||
| @@ -275,127 +275,67 @@ def l_adic_failure_from_data( B, l, tablel, M, N ): | |||
| 275 | 275 | ||
| 276 | return l^(r*n-tablel[m-1][0][n-1]) | 276 | return l^(r*n-tablel[m-1][0][n-1]) |
| 277 | 277 | ||
| 278 | # Computes the l-divisibility parameters of G over Q4, given a good basis b | 278 | # Returns the l-dvisibility parameters of G over Q, given a good basis gb of G, |
| 279 | # as a list of pairs (di,hi). | ||
| 280 | def parameters_Q( gb, l ): | ||
| 281 | ret = [] | ||
| 282 | for i in range( len( gb ) ): | ||
| 283 | for j in gb[i]: | ||
| 284 | ret.append( (i,0) ) | ||
| 285 | return ret | ||
| 286 | |||
| 287 | # Computes the l-divisibility parameters of G over Q4, given a good basis gb | ||
| 279 | # over Q for G. Returns a list of pairs (di,hi). | 288 | # over Q for G. Returns a list of pairs (di,hi). |
| 280 | # If l is odd it just uses the good basis given to compute the parameters. | 289 | # If l is odd it just uses the good basis given to compute the parameters. |
| 290 | # If l=2, it uses the results of PST-2. | ||
| 281 | def parameters_Q4( gb, l ): | 291 | def parameters_Q4( gb, l ): |
| 282 | # Converts from "good basis format" to simple list | ||
| 283 | b = [] | ||
| 284 | for x in gb: | ||
| 285 | b += x | ||
| 286 | ret = [] | ||
| 287 | |||
| 288 | if l != 2: | 292 | if l != 2: |
| 289 | for i in range( len( gb ) ): | 293 | return parameters_Q( gb, l ) |
| 290 | for j in gb[i]: | ||
| 291 | ret.append( (i,0) ) | ||
| 292 | return ret | ||
| 293 | else: | 294 | else: |
| 294 | R.<y> = PolynomialRing( QQ ) | 295 | # Converts from "good basis format" to simple list |
| 295 | pol = R(y^2+1) | 296 | b = [] |
| 296 | Q4.<eye> = NumberField( pol ) # I already use i for other things | 297 | for x in gb: |
| 297 | 298 | b += x | |
| 298 | # Factorize basis elements over Q4 and so on. | 299 | |
| 299 | d = [] | 300 | M = exponent_matrix( b ) |
| 300 | B = [] | ||
| 301 | h = [] | ||
| 302 | ideals_list = set() | ||
| 303 | M = [] # Exponent matrix of the Bi's | ||
| 304 | |||
| 305 | # Pre-process to find all ideals appearing in the factorization and fix | ||
| 306 | # a chosen generator for each of them. This is important in order to | ||
| 307 | # compute the "sign" (h-parameter) of an element with respect to it Bi. | ||
| 308 | for g in b: | ||
| 309 | factorization_list = list( Q4.ideal(g).factor() ) | ||
| 310 | ideals_list |= set( [ x[0] for x in factorization_list ] ) | ||
| 311 | ideals_list = list( ideals_list ) | ||
| 312 | # Chooses a generator of each principal ideal in the list | ||
| 313 | irreducibles_list = [ J.gens_reduced()[0] for J in ideals_list ] | ||
| 314 | 301 | ||
| 315 | # Compute the Q4-parameters of the given basis b. Also computes the | 302 | # Thanks to my terrible notation, the elements of b are what are called |
| 316 | # exponent matrix of the Bi's | 303 | # g_i in the article, while the elements of bb will be the b_i's. |
| 317 | for g in b: | 304 | bb = [ abs(b[i]) ^ (2^(-divisibility(M[i],2))) for i in range(len(b)) ] |
| 318 | factorization_list = list( Q4.ideal(g).factor() ) | ||
| 319 | exps = [ x[1] for x in factorization_list ] | ||
| 320 | d.append( divisibility( exps, l ) ) | ||
| 321 | Bg = 1 | ||
| 322 | for j in range(len(factorization_list)): | ||
| 323 | a = 0 | ||
| 324 | for i in range( len( ideals_list ) ): | ||
| 325 | if ideals_list[i] == factorization_list[j][0]: | ||
| 326 | a = irreducibles_list[i] | ||
| 327 | break | ||
| 328 | Bg *= a ^ (exps[j]/(l^d[-1])) | ||
| 329 | B.append(Bg) | ||
| 330 | u = g / (Bg^(l^d[-1])) | ||
| 331 | if not u.is_unit(): | ||
| 332 | print "Error: g is not the right power of the computed Bg." | ||
| 333 | print "g:", g, ", Bg:", Bg, ", exponent:", l^d[-1] | ||
| 334 | if u == 1: | ||
| 335 | h.append( 0 ) | ||
| 336 | elif u == -1: | ||
| 337 | h.append( 1 ) | ||
| 338 | else: | ||
| 339 | h.append( 2 ) | ||
| 340 | 305 | ||
| 341 | # Make the exponent matrix M (for now as a list of rows) | 306 | # Computing a combination of bb elements of the form 2 * square. |
| 342 | for g in B: | 307 | MM = exponent_matrix( bb + [2] ).change_ring( GF( 2 ) ) |
| 343 | row = [0] * len(ideals_list) | ||
| 344 | for i in range(len(ideals_list)): | ||
| 345 | I = ideals_list[i] | ||
| 346 | ee = 1 | ||
| 347 | while (I^ee).divides(g): | ||
| 348 | ee += 1 | ||
| 349 | row[i] = ee-1 | ||
| 350 | M.append(row) | ||
| 351 | 308 | ||
| 352 | # If the Bi's are not strongly independent, apply the algorithm (only | 309 | for a in MM.kernel().basis(): |
| 353 | # once) to produce a new basis. The new basis has maximal parameters. | 310 | if a[-1] != 0: |
| 354 | coeffs = find_combination( matrix(M), l ) | 311 | # the vector a[0:-1] gives the coefficients for a combination |
| 355 | if coeffs != []: | 312 | # of the b_i's of the form 2 * square |
| 313 | |||
| 314 | # Basis elements that actually appear in the combination | ||
| 315 | c = [ b[i] for i in range(len(a[0:-1])) if a[i] != 0 ] | ||
| 356 | 316 | ||
| 357 | maxi = -1 | 317 | # Return the parameters, changing only the ones fo the element |
| 358 | maxd = -1 | 318 | # of highest divisibility that appears in the combination. |
| 359 | for i in range(len(d)): | 319 | ret = [] |
| 360 | if d[i] > maxd and coeffs[i] != 0: | 320 | div_max = -1 |
| 361 | maxd = d[i] | 321 | ind_max = -1 |
| 362 | maxi = i | 322 | for i in range(len(b)): |
| 323 | ret.append( (divisibility(M[i],2), 1-max(0,sgn(b[i]))) ) | ||
| 324 | if a[i] != 0 and ret[i][0] > div_max: | ||
| 325 | div_max = ret[i][0] | ||
| 326 | ind_max = i | ||
| 327 | d1, h1 = ret[ind_max] | ||
| 328 | if d1 == 1: | ||
| 329 | h1 = 1 - h1 | ||
| 330 | elif d1 == 0: | ||
| 331 | h1 = 2 | ||
| 332 | ret[ind_max] = ( d1+1, h1 ) | ||
| 363 | 333 | ||
| 364 | x = [(a/coeffs[maxi]).lift() for a in coeffs] # Now a vector of int | 334 | return ret |
| 365 | 335 | ||
| 366 | new_element = 1 | 336 | return parameters_Q( gb, 2 ) |
| 367 | for i in range(len(d)): | ||
| 368 | new_element *= b[i]^( x[i] * l^(d[maxi]-d[i]) ) | ||
| 369 | |||
| 370 | b[maxi] = new_element | ||
| 371 | 337 | ||
| 372 | # Compute new B, d and so on. | ||
| 373 | factorization_list = list( Q4.ideal(b[maxi]).factor() ) | ||
| 374 | exps = [ x[1] for x in factorization_list ] | ||
| 375 | d[maxi] = divisibility( exps, l ) | ||
| 376 | Bg = 1 | ||
| 377 | 338 | ||
| 378 | for j in range(len(factorization_list)): | ||
| 379 | a = 0 | ||
| 380 | for i in range( len( ideals_list ) ): | ||
| 381 | if ideals_list[i] == factorization_list[j][0]: | ||
| 382 | a = irreducibles_list[i] | ||
| 383 | break | ||
| 384 | Bg *= a ^ (exps[j]/(l^d[maxi])) | ||
| 385 | B[maxi] = Bg | ||
| 386 | M[maxi] = [ x[1] for x in list( Q4.ideal(Bg).factor() ) ] | ||
| 387 | u = b[maxi] / (Bg^(l^d[maxi])) | ||
| 388 | if not u.is_unit(): | ||
| 389 | print "Error: new element is not the right power of B." | ||
| 390 | print "New el.:", b[maxi], ", B:", Bg, ", exponent:", l^d[maxi] | ||
| 391 | if u == 1: | ||
| 392 | h[maxi] = 0 | ||
| 393 | elif u == -1: | ||
| 394 | h[maxi] = 1 | ||
| 395 | else: | ||
| 396 | h[maxi] = 2 | ||
| 397 | |||
| 398 | return [(d[i],h[i]) for i in range(len(d))] | ||
| 399 | 339 | ||
| 400 | # Uses Theorem 18 to compute the degree of Kummer extensions. | 340 | # Uses Theorem 18 to compute the degree of Kummer extensions. |
| 401 | def compute_vl( p, n, m, r ): | 341 | def compute_vl( p, n, m, r ): |
| @@ -405,6 +345,28 @@ def compute_vl( p, n, m, r ): | |||
| 405 | 345 | ||
| 406 | return M - m + r*n - sum( ni ) | 346 | return M - m + r*n - sum( ni ) |
| 407 | 347 | ||
| 348 | # Computes a basis for G from a set of generators. | ||
| 349 | # Returns a pair (B,torsion) where B is a list of rational numbers and torsion | ||
| 350 | # is true if -1 is in G and false otherwise. | ||
| 351 | def generators_to_basis( G ): | ||
| 352 | (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) | ||
| 353 | BM = BM.echelon_form() | ||
| 354 | BM_primes.append(-1) | ||
| 355 | B = [] | ||
| 356 | torsion = False | ||
| 357 | |||
| 358 | for r in BM.rows(): | ||
| 359 | gr = product( [ BM_primes[i]^r[i] for i in range(len(r)) ] ) | ||
| 360 | if gr == -1: | ||
| 361 | torsion = True | ||
| 362 | break | ||
| 363 | elif gr == 1: | ||
| 364 | break | ||
| 365 | else: | ||
| 366 | B.append(gr) | ||
| 367 | |||
| 368 | return (B,torsion) | ||
| 369 | |||
| 408 | # Given any basis b of a group G computes an l-good basis for G. This is done | 370 | # Given any basis b of a group G computes an l-good basis for G. This is done |
| 409 | # using the algorithm outlined in the proof of Theorem 14 of (Debry-Perucca). | 371 | # using the algorithm outlined in the proof of Theorem 14 of (Debry-Perucca). |
| 410 | def make_good_basis( b, l ): | 372 | def make_good_basis( b, l ): |
| @@ -549,22 +511,7 @@ def TotalKummerFailure( G ): | |||
| 549 | # return any value. | 511 | # return any value. |
| 550 | def total_kummer_failure( G, output ): | 512 | def total_kummer_failure( G, output ): |
| 551 | 513 | ||
| 552 | # Computing a basis. | 514 | B, torsion = generators_to_basis( G ) |
| 553 | (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) | ||
| 554 | BM = BM.echelon_form() | ||
| 555 | BM_primes.append(-1) | ||
| 556 | B = [] | ||
| 557 | torsion = False | ||
| 558 | |||
| 559 | for r in BM.rows(): | ||
| 560 | gr = product( [ BM_primes[i]^r[i] for i in range(len(r)) ] ) | ||
| 561 | if gr == -1: | ||
| 562 | torsion = True | ||
| 563 | break | ||
| 564 | elif gr == 1: | ||
| 565 | break | ||
| 566 | else: | ||
| 567 | B.append(gr) | ||
| 568 | 515 | ||
| 569 | if len(B) == 0: | 516 | if len(B) == 0: |
| 570 | print "G is torsion. The extension is cyclotomic. Stopping." | 517 | print "G is torsion. The extension is cyclotomic. Stopping." |
