kummer-degrees

Compute the degree of Kummer extensions
git clone https://git.tronto.net/kummer-degrees
Download | Log | Files | Refs | README | LICENSE

commit cf6c4f80c1eb5f77d14816bcc6323e01c35d94ce
parent 3062ce67bb0240a47841bfb954ca79a2d8d64768
Author: Sebastiano Tronto <sebastiano.tronto@gmail.com>
Date:   Tue, 30 Jul 2019 16:25:26 +0200

Using results of PST-2 to compute parameters over Q4 directly

Diffstat:
A.kummer_degree.sage.swp | 0
A.parameters_Q4_new.sage.swp | 0
Mkummer_degree.sage | 211++++++++++++++++++++++++++++++-------------------------------------------------
Aparameters_Q4_new.sage | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aparameters_Q4_old.sage | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 262 insertions(+), 132 deletions(-)

diff --git a/.kummer_degree.sage.swp b/.kummer_degree.sage.swp Binary files differ. diff --git a/.parameters_Q4_new.sage.swp b/.parameters_Q4_new.sage.swp Binary files differ. diff --git a/kummer_degree.sage b/kummer_degree.sage @@ -275,127 +275,67 @@ def l_adic_failure_from_data( B, l, tablel, M, N ): return l^(r*n-tablel[m-1][0][n-1]) -# Computes the l-divisibility parameters of G over Q4, given a good basis b +# Returns the l-dvisibility parameters of G over Q, given a good basis gb of G, +# as a list of pairs (di,hi). +def parameters_Q( gb, l ): + ret = [] + for i in range( len( gb ) ): + for j in gb[i]: + ret.append( (i,0) ) + return ret + +# Computes the l-divisibility parameters of G over Q4, given a good basis gb # over Q for G. Returns a list of pairs (di,hi). # If l is odd it just uses the good basis given to compute the parameters. +# If l=2, it uses the results of PST-2. def parameters_Q4( gb, l ): - # Converts from "good basis format" to simple list - b = [] - for x in gb: - b += x - ret = [] - if l != 2: - for i in range( len( gb ) ): - for j in gb[i]: - ret.append( (i,0) ) - return ret + return parameters_Q( gb, l ) else: - R.<y> = PolynomialRing( QQ ) - pol = R(y^2+1) - Q4.<eye> = NumberField( pol ) # I already use i for other things - - # Factorize basis elements over Q4 and so on. - d = [] - B = [] - h = [] - ideals_list = set() - M = [] # Exponent matrix of the Bi's - - # Pre-process to find all ideals appearing in the factorization and fix - # a chosen generator for each of them. This is important in order to - # compute the "sign" (h-parameter) of an element with respect to it Bi. - for g in b: - factorization_list = list( Q4.ideal(g).factor() ) - ideals_list |= set( [ x[0] for x in factorization_list ] ) - ideals_list = list( ideals_list ) - # Chooses a generator of each principal ideal in the list - irreducibles_list = [ J.gens_reduced()[0] for J in ideals_list ] - - # Compute the Q4-parameters of the given basis b. Also computes the - # exponent matrix of the Bi's - for g in b: - factorization_list = list( Q4.ideal(g).factor() ) - exps = [ x[1] for x in factorization_list ] - d.append( divisibility( exps, l ) ) - Bg = 1 - for j in range(len(factorization_list)): - a = 0 - for i in range( len( ideals_list ) ): - if ideals_list[i] == factorization_list[j][0]: - a = irreducibles_list[i] - break - Bg *= a ^ (exps[j]/(l^d[-1])) - B.append(Bg) - u = g / (Bg^(l^d[-1])) - if not u.is_unit(): - print "Error: g is not the right power of the computed Bg." - print "g:", g, ", Bg:", Bg, ", exponent:", l^d[-1] - if u == 1: - h.append( 0 ) - elif u == -1: - h.append( 1 ) - else: - h.append( 2 ) - - # Make the exponent matrix M (for now as a list of rows) - for g in B: - row = [0] * len(ideals_list) - for i in range(len(ideals_list)): - I = ideals_list[i] - ee = 1 - while (I^ee).divides(g): - ee += 1 - row[i] = ee-1 - M.append(row) - - # If the Bi's are not strongly independent, apply the algorithm (only - # once) to produce a new basis. The new basis has maximal parameters. - coeffs = find_combination( matrix(M), l ) - if coeffs != []: - - maxi = -1 - maxd = -1 - for i in range(len(d)): - if d[i] > maxd and coeffs[i] != 0: - maxd = d[i] - maxi = i - - x = [(a/coeffs[maxi]).lift() for a in coeffs] # Now a vector of int - - new_element = 1 - for i in range(len(d)): - new_element *= b[i]^( x[i] * l^(d[maxi]-d[i]) ) - - b[maxi] = new_element - - # Compute new B, d and so on. - factorization_list = list( Q4.ideal(b[maxi]).factor() ) - exps = [ x[1] for x in factorization_list ] - d[maxi] = divisibility( exps, l ) - Bg = 1 - - for j in range(len(factorization_list)): - a = 0 - for i in range( len( ideals_list ) ): - if ideals_list[i] == factorization_list[j][0]: - a = irreducibles_list[i] - break - Bg *= a ^ (exps[j]/(l^d[maxi])) - B[maxi] = Bg - M[maxi] = [ x[1] for x in list( Q4.ideal(Bg).factor() ) ] - u = b[maxi] / (Bg^(l^d[maxi])) - if not u.is_unit(): - print "Error: new element is not the right power of B." - print "New el.:", b[maxi], ", B:", Bg, ", exponent:", l^d[maxi] - if u == 1: - h[maxi] = 0 - elif u == -1: - h[maxi] = 1 - else: - h[maxi] = 2 - - return [(d[i],h[i]) for i in range(len(d))] + # Converts from "good basis format" to simple list + b = [] + for x in gb: + b += x + + M = exponent_matrix( b ) + + # Thanks to my terrible notation, the elements of b are what are called + # g_i in the article, while the elements of bb will be the b_i's. + bb = [ abs(b[i]) ^ (2^(-divisibility(M[i],2))) for i in range(len(b)) ] + + # Computing a combination of bb elements of the form 2 * square. + MM = exponent_matrix( bb + [2] ).change_ring( GF( 2 ) ) + + for a in MM.kernel().basis(): + if a[-1] != 0: + # the vector a[0:-1] gives the coefficients for a combination + # of the b_i's of the form 2 * square + + # Basis elements that actually appear in the combination + c = [ b[i] for i in range(len(a[0:-1])) if a[i] != 0 ] + + # Return the parameters, changing only the ones fo the element + # of highest divisibility that appears in the combination. + ret = [] + div_max = -1 + ind_max = -1 + for i in range(len(b)): + ret.append( (divisibility(M[i],2), 1-max(0,sgn(b[i]))) ) + if a[i] != 0 and ret[i][0] > div_max: + div_max = ret[i][0] + ind_max = i + d1, h1 = ret[ind_max] + if d1 == 1: + h1 = 1 - h1 + elif d1 == 0: + h1 = 2 + ret[ind_max] = ( d1+1, h1 ) + + return ret + + return parameters_Q( gb, 2 ) + + # Uses Theorem 18 to compute the degree of Kummer extensions. def compute_vl( p, n, m, r ): @@ -405,6 +345,28 @@ def compute_vl( p, n, m, r ): return M - m + r*n - sum( ni ) +# Computes a basis for G from a set of generators. +# Returns a pair (B,torsion) where B is a list of rational numbers and torsion +# is true if -1 is in G and false otherwise. +def generators_to_basis( G ): + (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) + BM = BM.echelon_form() + BM_primes.append(-1) + B = [] + torsion = False + + for r in BM.rows(): + gr = product( [ BM_primes[i]^r[i] for i in range(len(r)) ] ) + if gr == -1: + torsion = True + break + elif gr == 1: + break + else: + B.append(gr) + + return (B,torsion) + # Given any basis b of a group G computes an l-good basis for G. This is done # using the algorithm outlined in the proof of Theorem 14 of (Debry-Perucca). def make_good_basis( b, l ): @@ -549,22 +511,7 @@ def TotalKummerFailure( G ): # return any value. def total_kummer_failure( G, output ): - # Computing a basis. - (BM,BM_primes) = exponent_matrix_with_sign_and_primes( G ) - BM = BM.echelon_form() - BM_primes.append(-1) - B = [] - torsion = False - - for r in BM.rows(): - gr = product( [ BM_primes[i]^r[i] for i in range(len(r)) ] ) - if gr == -1: - torsion = True - break - elif gr == 1: - break - else: - B.append(gr) + B, torsion = generators_to_basis( G ) if len(B) == 0: print "G is torsion. The extension is cyclotomic. Stopping." diff --git a/parameters_Q4_new.sage b/parameters_Q4_new.sage @@ -0,0 +1,60 @@ +# Returns the l-dvisibility parameters of G over Q, given a good basis gb of G, +# as a list of pairs (di,hi). +def parameters_Q( gb, l ): + ret = [] + for i in range( len( gb ) ): + for j in gb[i]: + ret.append( (i,0) ) + return ret + +# Computes the l-divisibility parameters of G over Q4, given a good basis gb +# over Q for G. Returns a list of pairs (di,hi). +# If l is odd it just uses the good basis given to compute the parameters. +# If l=2, it uses the results of PST-2. +def parameters_Q4_new( gb, l ): + if l != 2: + return parameters_Q( gb, l ) + else: + # Converts from "good basis format" to simple list + b = [] + for x in gb: + b += x + + M = exponent_matrix( b ) + + # Thanks to my terrible notation, the elements of b are what are called + # g_i in the article, while the elements of bb will be the b_i's. + bb = [ abs(b[i]) ^ (2^(-divisibility(M[i],2))) for i in range(len(b)) ] + + # Computing a combination of bb elements of the form 2 * square. + MM = exponent_matrix( bb + [2] ).change_ring( GF( 2 ) ) + + for a in MM.kernel().basis(): + if a[-1] != 0: + # the vector a[0:-1] gives the coefficients for a combination + # of the b_i's of the form 2 * square + + # Basis elements that actually appear in the combination + c = [ b[i] for i in range(len(a[0:-1])) if a[i] != 0 ] + + # Return the parameters, changing only the ones fo the element + # of highest divisibility that appears in the combination. + ret = [] + div_max = -1 + ind_max = -1 + for i in range(len(b)): + ret.append( (divisibility(M[i],2), 1-max(0,sgn(b[i]))) ) + if a[i] != 0 and ret[i][0] > div_max: + div_max = ret[i][0] + ind_max = i + d1, h1 = ret[ind_max] + if d1 == 1: + h1 = 1 - h1 + elif d1 == 0: + h1 = 2 + ret[ind_max] = ( d1+1, h1 ) + + return ret + + return parameters_Q( gb, 2 ) + diff --git a/parameters_Q4_old.sage b/parameters_Q4_old.sage @@ -0,0 +1,123 @@ +# Computes the l-divisibility parameters of G over Q4, given a good basis gb +# over Q for G. Returns a list of pairs (di,hi). +# If l is odd it just uses the good basis given to compute the parameters. +def parameters_Q4( gb, l ): + # Converts from "good basis format" to simple list + b = [] + for x in gb: + b += x + ret = [] + + if l != 2: + for i in range( len( gb ) ): + for j in gb[i]: + ret.append( (i,0) ) + return ret + else: + R.<y> = PolynomialRing( QQ ) + pol = R(y^2+1) + Q4.<eye> = NumberField( pol ) # I already use i for other things + + # Factorize basis elements over Q4 and so on. + d = [] + B = [] + h = [] + ideals_list = set() + M = [] # Exponent matrix of the Bi's + + # Pre-process to find all ideals appearing in the factorization and fix + # a chosen generator for each of them. This is important in order to + # compute the "sign" (h-parameter) of an element with respect to it Bi. + for g in b: + factorization_list = list( Q4.ideal(g).factor() ) + ideals_list |= set( [ x[0] for x in factorization_list ] ) + ideals_list = list( ideals_list ) + # Chooses a generator of each principal ideal in the list + irreducibles_list = [ J.gens_reduced()[0] for J in ideals_list ] + + # Compute the Q4-parameters of the given basis b. Also computes the + # exponent matrix of the Bi's + for g in b: + factorization_list = list( Q4.ideal(g).factor() ) + exps = [ x[1] for x in factorization_list ] + d.append( divisibility( exps, l ) ) + Bg = 1 + for j in range(len(factorization_list)): + a = 0 + for i in range( len( ideals_list ) ): + if ideals_list[i] == factorization_list[j][0]: + a = irreducibles_list[i] + break + Bg *= a ^ (exps[j]/(l^d[-1])) + B.append(Bg) + u = g / (Bg^(l^d[-1])) + if not u.is_unit(): + print "Error: g is not the right power of the computed Bg." + print "g:", g, ", Bg:", Bg, ", exponent:", l^d[-1] + if u == 1: + h.append( 0 ) + elif u == -1: + h.append( 1 ) + else: + h.append( 2 ) + + # Make the exponent matrix M (for now as a list of rows) + for g in B: + row = [0] * len(ideals_list) + for i in range(len(ideals_list)): + I = ideals_list[i] + ee = 1 + while (I^ee).divides(g): + ee += 1 + row[i] = ee-1 + M.append(row) + + # If the Bi's are not strongly independent, apply the algorithm (only + # once) to produce a new basis. The new basis has maximal parameters. + coeffs = find_combination( matrix(M), l ) + if coeffs != []: + + maxi = -1 + maxd = -1 + for i in range(len(d)): + if d[i] > maxd and coeffs[i] != 0: + maxd = d[i] + maxi = i + + x = [(a/coeffs[maxi]).lift() for a in coeffs] # Now a vector of int + + new_element = 1 + for i in range(len(d)): + new_element *= b[i]^( x[i] * l^(d[maxi]-d[i]) ) + + b[maxi] = new_element + + # Compute new B, d and so on. + factorization_list = list( Q4.ideal(b[maxi]).factor() ) + exps = [ x[1] for x in factorization_list ] + d[maxi] = divisibility( exps, l ) + Bg = 1 + + for j in range(len(factorization_list)): + a = 0 + for i in range( len( ideals_list ) ): + if ideals_list[i] == factorization_list[j][0]: + a = irreducibles_list[i] + break + Bg *= a ^ (exps[j]/(l^d[maxi])) + B[maxi] = Bg + M[maxi] = [ x[1] for x in list( Q4.ideal(Bg).factor() ) ] + u = b[maxi] / (Bg^(l^d[maxi])) + if not u.is_unit(): + print "Error: new element is not the right power of B." + print "New el.:", b[maxi], ", B:", Bg, ", exponent:", l^d[maxi] + if u == 1: + h[maxi] = 0 + elif u == -1: + h[maxi] = 1 + else: + h[maxi] = 2 + + return [(d[i],h[i]) for i in range(len(d))] + +