Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download

All published worksheets from http://sagenb.org

Views: 168742
Image: ubuntu2004
################################################################################################ # # On the density of abelian surfaces with Tate-Shafarevich group of order five times a square # # Authors: Stefan Keil # Date: YY-MM-DD 12-05-10 # # Comments: # This is a running version. # We first define the methods used for the calculations. # Then there are the methods to start Step 0, 1 and 2, respectively. # # There is one thing to be improved: # In 'add_image_of_coker' or more precise in # 'get_mod_N_reduced_non_trivial_images_as_a_list_in_prime_factors' # very complicated prime ideal factorizations might occur. # Another approach working modulo some primes might be faster. # (In case the image (mod N-th powers) is a unit, the method # first tries to skip this factorization and just assumes that # the image (mod N-th powers) is the trivial equivalence class. # If this gives an error, it tries the factorization and prompts: # 'try ignore_units=0'. In case the image (mod N-th powers) # is NOT a unit, the factorization is always done.) # # 12-05-07: Fixed an error which could occur in rare cases # for rank=1 curves, and was more likely in case rank # bigger or equal to 2. # 12-05-10: Changed title. # #################################################################################################
############################################### ##### METHODS USED FOR STEP 1 AND STEP 2 ################################################
## CREATES (OR EXTENDS) A DATABASE WITH EASY DATA OF ELLIPTIC CURVES (including conductor) ## The unknown data is: ## rank=-1; ## MWgenerators=[]; ## dual_MWgenerators=[]; ## basis_of_image_of_dual_coker=[]; ## basis_of_image_of_coker=[]; ## dim_coker_eta=-1; ################################################################# ## If lower_bound equals zero, a new database will be created. ## If this value is unequal to zero, sage expects to get an old_list ## which contains exactely the data up to the lower_bound. ## Creates all elliptic curves E_d, s.t. d=i/j, i and j coprime ## positive integers, and lower_bound< i,j <= bound. ## l has to be 5 or 7. ################################################################## def create_database(l, bound, lower_bound=0, old_list=[]): if lower_bound==0: new_list=[] else: new_list=old_list; ##### go through all rational numbers with numerator and denominator bounded by the given bound for i in range(1,bound+1): # numerator for j in range(1,bound+1): # denominator if gcd(i,j)==1: # to check whether i/j was not treated before # check, if we have not already calculated the data if (i>lower_bound or j>lower_bound) and (l==5 or i+j>2): new_curve=get_basic_curve(i,j,l); new_list.append(new_curve); return new_list; ## CREATES THE BASIC DATA (including conductor) OF THE ELLIPTIC CURVE E_d, d=i/j, for the prime l=5 or 7 ################################################################################################### def get_basic_curve(i,j,l): if l==5: d1=i*j; #yields primes with split mult red, kernel not on identity comp. d2=i^2+11*i*j-j^2; # yields primes with bad red, kernel on identity comp. # store if the d-value is a fifth power, i.e., the dual curve has torsion d_is_fifth_power=0; if floor(list(pari(d1).sqrtn(5))[0])^5==d1: d_is_fifth_power=1; factors_of_d1 = list(factor(d1)); #factors of d1 factors_of_d2 = list(factor(d2)); #factors of d2 split_kernel_NOT_on_id=[]; # primes with split mult red, kernel not on id. comp. split_kernel_on_id=[]; # primes with split mult red, kernel on id. comp. non_split=[]; # primes with non-split mult red, kernel on id. comp. add_con=0; # is 0 if red is not add at 5, 1 if red add v_5(Delta)=2, and 2 if red is add, v_5(Delta)=3. ##### All primes dividing d1 are in split_kernel_NOT_on_id, ##### the primes dividing d2 are distributed among split_kernel_on_id, non_split and add_con. set_S_of_interesting_primes=[]; for k in range(0,len(factors_of_d1)): split_kernel_NOT_on_id.append(factors_of_d1[k][0]); set_S_of_interesting_primes.append(factors_of_d1[k][0]); for k in range(0,len(factors_of_d2)): set_S_of_interesting_primes.append(factors_of_d2[k][0]); if factors_of_d2[k][0] % 5==1: split_kernel_on_id.append(factors_of_d2[k][0]); if factors_of_d2[k][0] % 5==4: non_split.append(factors_of_d2[k][0]); if factors_of_d2[k][0]==5: if factors_of_d2[k][1]<=2: add_con=1; if factors_of_d2[k][1]>2: add_con=2; #for the conductor, see Silverman II, IV, Thm 10.2 conductor_of_E=1; for k in range(0, len(set_S_of_interesting_primes)): conductor_of_E=conductor_of_E*set_S_of_interesting_primes[k]; if add_con>0: conductor_of_E=conductor_of_E*5; if d1%5!=0 and d2%5!=0: set_S_of_interesting_primes.append(5); elif l==7: d1=i*j*(j-i); #yields primes with split mult red, kernel not on identity comp. d2=i^3-8*i^2*j+5*i*j^2+j^3; # yields primes with bad red, kernel on identity comp. # store if the d-value is a seventh power d_is_fifth_power=0; #if floor(list(pari(d1).sqrtn(7))[0])^7==d1: # d_is_fifth_power=1; factors_of_d1 = list(factor(d1)); #factors of d1 factors_of_d2 = list(factor(d2)); #factors of d2 split_kernel_NOT_on_id=[]; # primes with split mult red, kernel not on id. comp. split_kernel_on_id=[]; # primes with split mult red, kernel on id. comp. non_split=[]; # primes with non-split mult red, kernel on id. comp. add_con=0; # is 0 if red is not add at 7, 2 if red is add. ##### All primes dividing d1 are in split_kernel_NOT_on_id, ##### the primes dividing d2 are distributed among split_kernel_on_id, non_split and add_con. set_S_of_interesting_primes=[]; for k in range(0,len(factors_of_d1)): split_kernel_NOT_on_id.append(factors_of_d1[k][0]); set_S_of_interesting_primes.append(factors_of_d1[k][0]); for k in range(0,len(factors_of_d2)): set_S_of_interesting_primes.append(factors_of_d2[k][0]); if factors_of_d2[k][0] % 7==1: split_kernel_on_id.append(factors_of_d2[k][0]); if factors_of_d2[k][0] % 7==6: non_split.append(factors_of_d2[k][0]); if factors_of_d2[k][0]==7: add_con=2; #for the conductor, see Silverman II, IV, Thm 10.2 conductor_of_E=1; for k in range(0, len(set_S_of_interesting_primes)): conductor_of_E=conductor_of_E*set_S_of_interesting_primes[k]; if add_con>0: conductor_of_E=conductor_of_E*7; if d1%7!=0 and d2%7!=0: set_S_of_interesting_primes.append(7); rank=-1; MWgenerators=[]; dual_MWgenerators=[]; basis_of_image_of_dual_coker=[]; basis_of_image_of_coker=[]; dim_coker_eta=-1; return [i,j,d1,d2,set(split_kernel_NOT_on_id), set(split_kernel_on_id), set(non_split), add_con, rank, MWgenerators, dual_MWgenerators, basis_of_image_of_dual_coker, basis_of_image_of_coker, set_S_of_interesting_primes, d_is_fifth_power, dim_coker_eta, conductor_of_E]; ##### ADD THE ANALYTIC RANK INTO A DATABASE, ##### which already knows the conductor. ##### Only calculates the rank if it is "unknown", i.e., rank==-1. ##### (if a bound is given, only curves of conductor less or equal to that conductor_bound ##### will be considered. conductor_bound=0 means no bound.) def add_rank(loaded_list, l, bound=0, conductor_bound=0): total_number_of_curves=0; # total number of curves considered total_number_of_curves_with_rank_0=0; total_number_of_curves_with_rank_1=0; total_number_of_curves_with_rank_2=0; total_number_of_curves_with_rank_3=0; total_number_of_curves_with_rank_4=0; total_number_of_curves_with_rank_5=0; for kk in range(0,len(loaded_list)): # if the (analytic rank was not calculated yet, and the conductor is less or equal the given conductor_bound, # and i and j are less or equal to given bound if loaded_list[kk][8]==-1 and (loaded_list[kk][16]<conductor_bound+1 or conductor_bound==0) and ((loaded_list[kk][0]<bound+1 and loaded_list[kk][1]<bound+1) or bound==0): total_number_of_curves=total_number_of_curves+1; if total_number_of_curves%100==0: print total_number_of_curves; i=loaded_list[kk][0]; j=loaded_list[kk][1]; if l==5: E=EllipticCurve([i+j,i*j,i*j^2,0,0]); elif l==7: E=EllipticCurve([(j-i)^2+3*i*j,(j-i)*i^2*j,(j-i)*i^2*j^3,0,0]); rank=E.analytic_rank(); loaded_list[kk][8]=rank; ############################################################# ###### count curves of different rank ############################################################## if rank==0: total_number_of_curves_with_rank_0 = total_number_of_curves_with_rank_0 +1; #print("[i,j,rank]"); #print [i,j,rank]; elif rank==1: total_number_of_curves_with_rank_1 = total_number_of_curves_with_rank_1 +1; #print("[i,j,rank]"); #print [i,j,rank]; elif rank==2: total_number_of_curves_with_rank_2 = total_number_of_curves_with_rank_2 +1; #print("[i,j,rank]"); #print [i,j,rank]; elif rank==3: total_number_of_curves_with_rank_3 = total_number_of_curves_with_rank_3 +1; #print("[i,j,rank]"); #print [i,j,rank]; elif rank==4: total_number_of_curves_with_rank_4 = total_number_of_curves_with_rank_4 +1; #print("[i,j,rank]"); print [i,j,rank]; else: total_number_of_curves_with_rank_5 = total_number_of_curves_with_rank_5 +1; #print("[i,j,rank]"); print [i,j,rank]; ################################################################## print("Total number of elliptic curves: "+str(total_number_of_curves)); print("total_number_of_curves_with_rank_0: "+str(total_number_of_curves_with_rank_0 )); print("total_number_of_curves_with_rank_1: "+str(total_number_of_curves_with_rank_1)); print("total_number_of_curves_with_rank_2: "+str(total_number_of_curves_with_rank_2)); print("total_number_of_curves_with_rank_3: "+str(total_number_of_curves_with_rank_3)); print("total_number_of_curves_with_rank_4: "+str(total_number_of_curves_with_rank_4)); print("total_number_of_curves_with_rank_5: "+str(total_number_of_curves_with_rank_5)); ##### ADD MW GENS FOR RANK >0 CURVES IN A DATABASE (using height search), ##### which already contains the rank. ##### WARNING: It is not garanteed, that this will compute a MW-basis, ##### it rather produces a full sublattice, s.t. the points are not div by 5 (mod torsion) ##### WARNING 2: Only if rank <=1, it is proven, that the sublattice has finite index, ##### otherwise we have to assume this, i.e., we assume that the analytic and MW-rank are equal. ############################################################################################################ def add_gens_by_height_18(loaded_list, bound=0): exceptional_curves=[]; found_curves=[] # the variable x Q_x.<x>=QQ[]; for kk in range(0,len(loaded_list)): # only check curves of rank >0 and i,j<=bound (if bound unequal 0) if loaded_list[kk][8]>0 and ((loaded_list[kk][0]<bound+1 and loaded_list[kk][1]<bound+1) or bound==0): i=loaded_list[kk][0]; j=loaded_list[kk][1]; rank=loaded_list[kk][8]; MWgenerators=loaded_list[kk][9]; E=EllipticCurve([i+j,i*j,i*j^2,0,0]); torsion_point_of_E=E(0,0); #take the multipl-by-deg_of_phi_dual-isogeny multi_by_deg=E.multiplication_by_m(5); # multi_by_deg(x,y)=(reg_func_of_x(x,y),reg_func_of_y(x,y)) as regular functions reg_func_of_x=multi_by_deg[0](x,1); # if the MWgenerators havnt been calculated yet (and the curve is not on the "exceptional-list") if MWgenerators==[] and exceptional(i,j)==0: #print [i,j,rank]; lin_indep_points=E.point_search(height_limit=10,rank_bound=rank); if len(lin_indep_points)<rank: lin_indep_points=E.point_search(height_limit=18,rank_bound=rank); if len(lin_indep_points)<rank: print("couldnt find enough points with point search for [i,j,rank, #points]"); print [i,j,rank,len(lin_indep_points)]; exceptional_curves.append([i,j,rank,len(lin_indep_points)]); #if we found enough points, check if div by 5 if len(lin_indep_points)==rank: found_a_div_point=[]; # check if the points are divisible by 5 (mod torsion) and divide, if posible for ll in range(0,len(lin_indep_points)): #init as not divisible found_a_div_point.append(0); # there are 5 torsion points for lll in range(0,5): # if the lin indep point is not known to be div by 5 so far if found_a_div_point[ll]==0: point_to_check=lin_indep_points[ll]+lll*torsion_point_of_E; ##### check if point_to_check is divisible by 5 in E(QQ) # get all rational values of points P, s.t. x([5]P)=x_value_of_image_point solutions_x=get_solutions_x(point_to_check, reg_func_of_x); # if point_to_check is divisible by 5 if len(solutions_x)>0: print("POINT DIV BY 5. [i,j,rank,ll,lll,point_to_check,lin_indep_points]"); print [i,j,rank,ll,lll,point_to_check,lin_indep_points]; found_a_div_point[ll]=1; #divide by 5 chosen_x_value=min(solutions_x); point_to_check=E.lift_x(chosen_x_value); # pick the smallest of the two points if smaller_as(-point_to_check,point_to_check)==1: point_to_check=-point_to_check; lin_indep_points[ll]=point_to_check; MWgenerators=lin_indep_points; #double check that points belong to E, have infinite order and are lin indep basis_points=[]; for k in range(0,len(MWgenerators)): basis_points.append(E(MWgenerators[k][0],MWgenerators[k][1])); if MWgenerators!=basis_points: print("MWgenerators!=basis_points. [i,j,rank,MWgenerators,basis_points]");print [i,j,rank,MWgenerators,basis_points]; #print("Finish checking points belong to curves"); for k in range(0,len(MWgenerators)): if MWgenerators[k].order()!=oo: print("point not of order infty! [i,j,rank,MWgenerators[k],k]"); print [i,j,rank,MWgenerators[k],k]; #print("Finish checking points have order infty"); # check lin indep if rank>1: det_of_height_pairing=E.height_pairing_matrix(MWgenerators).determinant(); if det_of_height_pairing<0.5: print("det_of_height_pairing<0.5") print [i,j,rank,E.height_pairing_matrix(MWgenerators).determinant()]; #transform points into rational numbers for k in range(0,len(lin_indep_points)): lin_indep_points[k]=[lin_indep_points[k][0],lin_indep_points[k][1]]; #print("lin_indep_points"); print lin_indep_points; loaded_list[kk][9]=lin_indep_points; found_curves.append(loaded_list[kk]) #print loaded_list[kk] print("exceptional_curves"); print exceptional_curves; #print("found_curves"); print found_curves; ##### ADD MW GENS FOR RANK >0 CURVES IN A DATABASE (using MWgens), ##### which already contains the rank. ############################################################################################################ def add_gens_by_MWgens(loaded_list, bound=0): exceptional_curves=[]; considered_curves=[]; # the variable x Q_x.<x>=QQ[]; for kk in range(0,len(loaded_list)): # only check curves of rank >0 and i,j<=bound (if bound unequal 0) if loaded_list[kk][8]>0 and ((loaded_list[kk][0]<bound+1 and loaded_list[kk][1]<bound+1) or bound==0): i=loaded_list[kk][0]; j=loaded_list[kk][1]; rank=loaded_list[kk][8]; MWgenerators=loaded_list[kk][9]; E=EllipticCurve([i+j,i*j,i*j^2,0,0]); # if the MWgenerators havnt been calculated yet if MWgenerators==[]: #print [i,j,rank]; try: MWgenerators = E.gens(rank1_search=0,descent_second_limit=12,sat_bound=0); #transform points into rational numbers for k in range(0,len(MWgenerators)): MWgenerators[k]=[MWgenerators[k][0],MWgenerators[k][1]]; loaded_list[kk][9]=MWgenerators; considered_curves.append([i,j,rank,MWgenerators]); print [i,j,rank,MWgenerators]; except RuntimeError: print("RuntimeError"); print [i,j,rank]; exceptional_curves.append([i,j,rank]); print("exceptional_curves"); print exceptional_curves; #print("considered_curves"); print considered_curves; ##### ADD DUAL MW GENERATORS, IMAGE OF DUAL COKER, AND DIM COKER ETA INTO A DATABASE, ##### which already contains the rank and the MW generators ############################################################################################################ def add_dual_gens(loaded_list): for kk in range(0,len(loaded_list)): i=loaded_list[kk][0]; j=loaded_list[kk][1]; rank=loaded_list[kk][8]; MWgenerators=loaded_list[kk][9]; dual_MWgenerators=loaded_list[kk][10]; basis_of_image_of_dual_coker=loaded_list[kk][11]; basis_of_image_of_coker=loaded_list[kk][12]; set_S_of_interesting_primes=loaded_list[kk][13]; d_is_fifth_power=loaded_list[kk][14]; dim_coker_eta=loaded_list[kk][15]; conductor_of_E=loaded_list[kk][16]; # only check curves of positive rank and known MWgens and unknown dual_MWgens, # or curves of rank 0 with unknown dim_coker_eta if ((rank>0 and MWgenerators!=[] and dual_MWgenerators==[]) or (rank==0 and dim_coker_eta==-1)): #print [i,j,rank] #if the MWgens are known, calculate the dual MWgens #and the dim of the free part of the cokernel of eta if MWgenerators!=[]: E=EllipticCurve([i+j,i*j,i*j^2,0,0]); E_dual=EllipticCurve([i+j,i*j,i*j^2,5*i^3*j-10*i^2*j^2-5*i*j^3,i^5*j-10*i^4*j^2-5*i^3*j^3-15*i^2*j^4-i*j^5]); phi=EllipticCurveIsogeny(E, E(0,0), E_dual, 5); dual_MWgenerators_and_dim_of_free_coker_eta=get_dual_MWgenerators_and_dim_of_free_coker_eta(MWgenerators, E, E_dual, phi, d_is_fifth_power); else: dual_MWgenerators_and_dim_of_free_coker_eta=[[],0] dual_MWgenerators=dual_MWgenerators_and_dim_of_free_coker_eta[0]; dim_coker_eta=dual_MWgenerators_and_dim_of_free_coker_eta[1]+d_is_fifth_power; ################################################################### ###### basis of image of dual coker ###### calculate the image of MWgenerators in QQ^* mod fifth powers #################################################################### ###### start with the image of the 5-torsion; ignore other torsion image_of_dual_coker=[j*i^4] ###### run through a base of MW mod torsion for ii in range(len(MWgenerators)): image_of_dual_coker.append(get_image_of_point_of_dual_coker_in_QQ_star( MWgenerators[ii],j)); #print("image of dual cokernel is");print image_of_dual_coker; ###### reduce dual images modulo 5-th powers and remove trivial ones reduced_image_of_dual_coker= get_mod_N_reduced_non_trivial_dual_images_as_a_list_in_prime_factors( image_of_dual_coker, N=5); #print("reduced image of dual cokernel is"); print reduced_image_of_dual_coker; basis_of_image_of_dual_coker=get_basis_of(reduced_image_of_dual_coker, N=5); #print("basis_of_image_of_dual_coker"); print basis_of_image_of_dual_coker; loaded_list[kk][10]=dual_MWgenerators; loaded_list[kk][11]=basis_of_image_of_dual_coker; loaded_list[kk][15]=dim_coker_eta; ##### ADD BASIS OF IMAGE OF COKER AS PRIME FACTORISATION OF QQ(zeta_5)* (mod fifth powers) ##### into a data base which knows the rank and dual_MWgenerators ############################################################################################################ def add_image_of_coker(loaded_list): exceptions=[]; for kk in range(0,len(loaded_list)): # only consider rank>0 curves or those which have torsion, if rank is 0 if loaded_list[kk][8]>0 or (loaded_list[kk][14]==1 and loaded_list[kk][8]==0): i=loaded_list[kk][0]; j=loaded_list[kk][1]; rank=loaded_list[kk][8]; MWgenerators=loaded_list[kk][9]; dual_MWgenerators=loaded_list[kk][10]; basis_of_image_of_dual_coker=loaded_list[kk][11]; basis_of_image_of_coker=loaded_list[kk][12]; set_S_of_interesting_primes=loaded_list[kk][13]; d_is_fifth_power=loaded_list[kk][14]; dim_coker_eta=loaded_list[kk][15]; conductor_of_E=loaded_list[kk][16]; ################################################################### ###### basis of image of coker ###### calculate the image of dual_MWgenerators in QQ(zeta_5)* mod fifth powers ##################################################################### ###### start with the image of the 5-torsion; ignore other torsion ###### (recall: there is 5-torsion iff d is a fifth power) image_of_coker=[] ###### the images in image_of_coker will be given as elements in K.<a>=CyclotomicField(5); # add the torsion point, if there is one if d_is_fifth_power==1: E_dual=EllipticCurve([i+j,i*j,i*j^2,5*i^3*j-10*i^2*j^2-5*i*j^3,i^5*j-10*i^4*j^2-5*i^3*j^3-15*i^2*j^4-i*j^5]); torsion_points=E_dual.torsion_points(); if torsion_points[0].order==5: torsion_point=torsion_points[0]; else: torsion_point=torsion_points[1]; image_of_coker.append(get_image_of_point_of_coker_in_QQ_zeta_5_star( [torsion_point[0],torsion_point[1]],i,j,a,K)); ###### run through a base of dual MW mod torsion and calculate the images for ii in range(len(dual_MWgenerators)): image_of_coker.append(get_image_of_point_of_coker_in_QQ_zeta_5_star( dual_MWgenerators[ii],i,j,a,K)); ###### Reduce images modulo 5-th powers and remove trivial ones; ###### and then take a basis from this. ###### Returns a list with elements in QQ(zeta_5) reduced_non_trivial_image_of_coker=[]; basis_of_image_of_coker=[]; if image_of_coker!=[]: #reduce image of coker mod fifth powers wrt to generators_of_prime_ideals_of_K; remove trivial ones #### ignore_units=1 means, that we assume that the image has trivial unit class reduced_non_trivial_image_of_coker=get_mod_N_reduced_non_trivial_images_as_a_list_in_prime_factors( K,a,unit_group_of_K, image_of_coker, set_S_of_interesting_primes, ignore_units=1, N=5); #print("reduced_non_trivial_image_of_coker"); print reduced_non_trivial_image_of_coker; #reduce the set of generators to a basis basis_of_image_of_coker=get_basis_of_mod_N_reduced_non_trivial_images( reduced_non_trivial_image_of_coker, N=5); # check if cardinality of basis equals expected value if dim_coker_eta!=len(basis_of_image_of_coker): print("try ignore_units=0 for [i,j,rank,d_is_fifth_power]") print [i,j,rank,d_is_fifth_power] reduced_non_trivial_image_of_coker=get_mod_N_reduced_non_trivial_images_as_a_list_in_prime_factors( K,a,unit_group_of_K, image_of_coker, set_S_of_interesting_primes, ignore_units=0, N=5); #print("reduced_non_trivial_image_of_coker"); print reduced_non_trivial_image_of_coker; #reduce the set of generators to a basis basis_of_image_of_coker=get_basis_of_mod_N_reduced_non_trivial_images( reduced_non_trivial_image_of_coker, N=5); if dim_coker_eta!=len(basis_of_image_of_coker): print("ERROR: calculated dim of coker of eta is unequal to the dim of its embedding in K* mod 5-th powers"); print("[i,j,rank,image_of_coker,dim_coker_eta, basis_of_image_of_coker]"); print [i,j,rank,image_of_coker,dim_coker_eta, basis_of_image_of_coker]; exceptions.append([i,j,rank,image_of_coker,dim_coker_eta, basis_of_image_of_coker]) loaded_list[kk][12]=basis_of_image_of_coker; print("exceptions"); print exceptions; # Given an isogeny eta between two elliptic curves E and E_dual, and given generators # of a finite index sublattice of the MW group of E, this method calculates a finite index # sublattice of the MW group of the dual curve, s.t. the degree of eta does not divide its index. # It also calculates the dim of the cokernel of the free part of the isogeny eta. ################################################################### # E_dual_has_torsion=0 (No), =1 (Yes), =2 (check extra) ##################################################################### def get_dual_MWgenerators_and_dim_of_free_coker_eta(MWgenerators, E, E_dual, eta, E_dual_has_torsion=2): dual_MWgenerators=[]; dim_coker_eta=0; rank=len(MWgenerators); if rank>0: # the variable x Q_x.<x>=QQ[]; #take the multipl-by-deg_of_eta-isogeny deg_of_eta=eta.degree(); multi_by_deg=E_dual.multiplication_by_m(deg_of_eta); # multi_by_deg(x,y)=(reg_func_of_x(x,y),reg_func_of_y(x,y)) as regular functions reg_func_of_x=multi_by_deg[0](x,1); # calculate torsion if E_dual_has_torsion>0: torsion_points_of_E_dual=E_dual.torsion_points(); if len(torsion_points_of_E_dual)>1: E_dual_has_torsion=1; else: E_dual_has_torsion=0; else: torsion_points_of_E_dual=[E_dual(0,1,0)]; #print("torsion_points_of_E_dual="+str(torsion_points_of_E_dual)); #calculate the images number_of_divisible_points=0; divided_image_points=[]; image_points_div_by_deg_eta=[]; for k in range(0,rank): image_point=eta(E(MWgenerators[k][0],MWgenerators[k][1])); #check if invers of image_point has smaller naive height if smaller_as(-image_point,image_point)==1: image_point=-image_point; divided_image_points.append(image_point); image_points_div_by_deg_eta.append(0); #print("divided_image_points: "+str(divided_image_points)); #go over all possible subgroups of the image and check if the points of this subgroup are div by deg_of_eta (mod torsion) for k in range(1,rank+1): #calculate all k-tuples of image_points_div_by_deg_eta, s.t. if k>=2 at least 2 points are not divisible by deg_of_eta # and one of these two points is the first entry in the tuple #init a counter for creating the k-tuples counter_for_tuples=[]; for kk in range(0,rank): if kk < k: counter_for_tuples.append(1); else: counter_for_tuples.append(0); #create the k-tuples while true: #create the next k-tuple tuple_to_check=[]; number_of_NOT_div_points=0; for kk in range(0,rank): if counter_for_tuples[kk]==1: if image_points_div_by_deg_eta[kk]==0: number_of_NOT_div_points=number_of_NOT_div_points+1; if number_of_NOT_div_points==1: tuple_to_check.insert(0,kk); else: tuple_to_check.insert(1,kk); else: tuple_to_check.append(kk); #if tuple has to be checked, i.e., #if k>=2 at least 2 points are not divisible by deg_of_eta if k==1 or number_of_NOT_div_points>1: #print("tuple_to_check: "+str(tuple_to_check)); # go over all lin comb. every point of these lin comb generates a different subgroup #init counter for lin_comb counter_for_lin_comb=[1]; for kk in range(1,k): counter_for_lin_comb.append(1); #calculate the lin_comb while true: #calc next comb lin_comb=divided_image_points[tuple_to_check[0]]; for kk in range(1,k): lin_comb=lin_comb+counter_for_lin_comb[kk]*divided_image_points[tuple_to_check[kk]]; lin_comb_div_by_deg_eta=0; # check if lin_comb is divisible by deg_of_eta in E'(QQ) (mod torsion) #go over all torsion points for torsion_point in torsion_points_of_E_dual: # if lin_comb (mod torsion) is not known to be div by deg_of_eta so far if lin_comb_div_by_deg_eta==0: point_to_check=lin_comb+torsion_point; # check if point_to_check is divisible by deg_of_eta in E'(QQ) # get all rational values of points P, s.t. x([deg_of_eta]P)=x_value_of_image_point solutions_x=get_solutions_x(point_to_check, reg_func_of_x); # if point_to_check is divisible by deg_of_eta if len(solutions_x)>0: #print("## point_to_check DIV BY deg_of_phi for tuple_to_check="+str(tuple_to_check)+" and counter_for_lin_comb="+str(counter_for_lin_comb)+" and torsion_point="+str(torsion_point)); lin_comb_div_by_deg_eta=1; #div by deg_of_eta chosen_x_value=min(solutions_x); lin_comb=E_dual.lift_x(chosen_x_value); # pick the smallest of the two points if smaller_as(-lin_comb,lin_comb)==1: lin_comb=-lin_comb; dim_coker_eta=dim_coker_eta+lin_comb_div_by_deg_eta; #store the new point, if lin_comb was divisible by deg_of_eta; then stop if lin_comb_div_by_deg_eta==1: #replace the point divided_image_points[tuple_to_check[0]]=lin_comb; image_points_div_by_deg_eta[tuple_to_check[0]]=1; break; #calc next counter for lin_comb if k>1: counter_for_lin_comb[k-1]=counter_for_lin_comb[k-1]+1; for kk in range(1,k-1): if counter_for_lin_comb[k-kk]==deg_of_eta: counter_for_lin_comb[k-kk]=1; counter_for_lin_comb[k-kk-1]=counter_for_lin_comb[k-kk-1]+1; #check if we are done if counter_for_lin_comb[1]==deg_of_eta: break; else: break; #increase counter for creating k-tuples by 1 #check which counter has to be moved position_to_change=rank; number_of_counter=k; empty_slot_inbetween=false; for kk in range(1,rank+1): #if we found the counter which will be moved if counter_for_tuples[rank-kk]==1 and empty_slot_inbetween: position_to_change=rank-kk; break; #as long as there hasnt been an empty slot elif counter_for_tuples[rank-kk]==1: number_of_counter=number_of_counter-1; #if the slot is empty else: empty_slot_inbetween=true; #if we are at the maximum position, end the while loop if number_of_counter==0: break; #move the counter counter_for_tuples[position_to_change]=0; for kk in range(position_to_change+1, rank): #first fill in the counters, then empty slots if number_of_counter<=k: counter_for_tuples[kk]=1; number_of_counter=number_of_counter+1; else: counter_for_tuples[kk]=0; dual_MWgenerators=order_points_by_increasing_height(divided_image_points); #print("dual_MWgenerators after dividing and sorting by height"); #print dual_MWgenerators; ########################################### # make 'basis' nicer ########################################### if rank>1: #go over all points in dual_MWgenerators in reversed order (in decreasing height) for k in range(0,rank): better_point=dual_MWgenerators[rank-1-k]; better_counter=None; # the 'positive-version' #init counter for lin_comb counter_for_lin_comb=[]; for kk in range(0,rank-1): counter_for_lin_comb.append(1); #go over all lin comb while true: #calculate lin comb, called test_point test_point=dual_MWgenerators[rank-1-k]; for kk in range(0,rank-1): if kk<rank-1-k: test_point=test_point+counter_for_lin_comb[kk]*dual_MWgenerators[kk]; else: test_point=test_point+counter_for_lin_comb[kk]*dual_MWgenerators[kk+1]; if smaller_as(test_point, better_point)==1: better_point=test_point; better_counter=counter_for_lin_comb[:]; #calc next counter for lin_comb counter_for_lin_comb[rank-2]=counter_for_lin_comb[rank-2]+1; for kk in range(2,rank): if counter_for_lin_comb[rank-kk]==deg_of_eta+1: counter_for_lin_comb[rank-kk]=1; counter_for_lin_comb[rank-kk-1]=counter_for_lin_comb[rank-kk-1]+1; #check if we are done if counter_for_lin_comb[0]==deg_of_eta+1: break; #print("[k, better_point, better_counter]= "+str([k,better_point, better_counter])); better_counter=None; # the 'negative-version' #init counter for lin_comb counter_for_lin_comb=[]; for kk in range(0,rank-1): counter_for_lin_comb.append(1); #go over all lin comb while true: #calculate lin comb, called test_point test_point=dual_MWgenerators[rank-1-k]; for kk in range(0,rank-1): if kk<rank-1-k: test_point=test_point-counter_for_lin_comb[kk]*dual_MWgenerators[kk]; else: test_point=test_point-counter_for_lin_comb[kk]*dual_MWgenerators[kk+1]; if smaller_as(test_point, better_point)==1: better_point=test_point; better_counter=counter_for_lin_comb[:]; #calc next counter for lin_comb counter_for_lin_comb[rank-2]=counter_for_lin_comb[rank-2]+1; for kk in range(2,rank): if counter_for_lin_comb[rank-kk]==deg_of_eta+1: counter_for_lin_comb[rank-kk]=1; counter_for_lin_comb[rank-kk-1]=counter_for_lin_comb[rank-kk-1]+1; #check if we are done if counter_for_lin_comb[0]==deg_of_eta+1: break; #print("[k, better_point, better_counter]= "+str([k,better_point, better_counter])); #save better_point if smaller_as(-better_point, better_point)==1: better_point=-better_point; dual_MWgenerators[rank-1-k]=better_point; #order points again in increasing order dual_MWgenerators=order_points_by_increasing_height(dual_MWgenerators); #print("dual_MWgenerators AFTER MAKING NICER"); print dual_MWgenerators; ###################################################### # transform data and return it ###################################################### #transform the dual points into lists of rational numbers for k in range(0,len(dual_MWgenerators)): dual_MWgenerators[k]=[dual_MWgenerators[k][0],dual_MWgenerators[k][1]] return [dual_MWgenerators, dim_coker_eta]; ################################################################ # NEED FOR: get_dual_MWgenerators_and_dim_of_free_coker_eta ###### check if the x-value of image_point has a rational preimage ###### under multiplication by 5 def get_solutions_x(image_point, reg_func_of_x): x_value_of_image_point=image_point[0]; fact_of_f=(reg_func_of_x-x_value_of_image_point).factor(); factorisation_of_f=list(fact_of_f); solutions_x=[]; # check if there is a lin factor for kk in range(0,len(factorisation_of_f)): #the exponent of the factor should be positiv if factorisation_of_f[kk][1]>0: if factorisation_of_f[kk][0].degree()==1: # the lin factor is not necessary normalized x_equals_0=factorisation_of_f[kk][0](0,0); x_equals_1=factorisation_of_f[kk][0](1,0); solutions_x.append(-x_equals_0/(x_equals_1-x_equals_0)); return solutions_x; ################################################################ # NEED FOR: get_dual_MWgenerators_and_dim_of_free_coker_eta def order_points_by_increasing_height(points): returnvalue=[]; if len(points)>0: returnvalue=[points[0]]; for kk in range(1,len(points)): for kkk in range(0,len(returnvalue)): if smaller_as(points[kk], returnvalue[kkk])==1: returnvalue.insert(kkk,points[kk]); break; elif kkk==len(returnvalue)-1: returnvalue.insert(kkk+1,points[kk]); return returnvalue; ################################################################ # NEED FOR: get_dual_MWgenerators_and_dim_of_free_coker_eta # returns 1, if P1 is smaller or equal as P2; 0 otherwise def smaller_as(P1,P2): returnvalue=0; if max(abs(P1[0].numerator()), abs(P1[0].denominator()))<max(abs(P2[0].numerator()), abs(P2[0].denominator())): returnvalue=1; else: if max(abs(P1[0].numerator()), abs(P1[0].denominator()))==max(abs(P2[0].numerator()), abs(P2[0].denominator())) and max(abs(P1[1].numerator()), abs(P1[1].denominator()))<=max(abs(P2[1].numerator()), abs(P2[1].denominator())): returnvalue=1; return returnvalue; ###### the map dual coker into QQ* def get_image_of_point_of_dual_coker_in_QQ_star(P,j): x=P[0]; y=P[1]; z=-j*x^2+(x+j^2)*y; #z=-x^2+(x+1)*y; return z; ###### image is a list of rational numbers. Returns a list of prime factorizations, whose exponents are reduced mod N def get_mod_N_reduced_non_trivial_dual_images_as_a_list_in_prime_factors(image, N=5): reduced_image=[]; ###### run through all rational numbers that span the image for i in range(len(image)): ###### factorize the i-th number spanning the image prime_factors=list(Rational(image[i]).factor()); ###### reduce exponents mod N=5 reduced_prime_factors=[]; ###### run through all prime factors for j in range(len(prime_factors)): reduced_exponent=Mod(prime_factors[j][1],N); ###### add primes having non-trivial exponent if reduced_exponent != 0: reduced_prime_factors.append([prime_factors[j][0],reduced_exponent]); ###### only add non-trivial images if len(reduced_prime_factors)>0: reduced_image.append(reduced_prime_factors); return reduced_image; ##### input is a list of lists, which consists of pairs, the first one a prime, ##### the second its exponent mod N, e.g. [[[2, 1], [3, 1], [5, 4]], [[2, 1], [5, 1]]] ##### Returns a subset of these lists which are a basis def get_basis_of(generators, N): # sort generators by number of occurring prime factors generators_in_new_order=[]; if len(generators)>0: generators_in_new_order.append(generators[0]); for k in range (1,len(generators)): #get the position where to put this generator new_position=0; running_variable=0; while len(generators[k])>len(generators_in_new_order[running_variable]) and new_position < len(generators_in_new_order): new_position=new_position+1; running_variable=running_variable+1; # this is just to prevent an error if running_variable==len(generators_in_new_order): running_variable=0; generators_in_new_order.insert(new_position, generators[k]); generators=generators_in_new_order; #reduce to basis basis=[]; #pick the first generating element as a basis element if len(generators)>0: basis.append(generators[0]); #check every other generating element if it is lin indep to the basis so far for i in range(1,len(generators)): basis.append(generators[i]) matrix_of_exponents=get_matrix_of_exponents(basis, N=5); if matrix_of_exponents.rank() != len(basis): basis.remove(generators[i]); return basis; ################################################################ # NEED FOR: get_basis_of # NEED FOR: STEP2 ###### calculates matrix of the exponents (mod N-th powers) ###### list_of_candidates is a list of primes factorizations, where the exponents are reduced mod N, ###### and trivial ones are already removed def get_matrix_of_exponents(list_of_candidates, N=5): number_of_candidates=len(list_of_candidates); primes=get_list_of_all_primes_in_increasing_order(list_of_candidates); #print "primes to consider are" #print primes number_of_primes=len(primes); ###### construct 'exponent-arrays' of the candidates matrix_of_exponents=[]; for i in range(number_of_candidates): exponents_of_candidate=[]; candidate=list_of_candidates[i]; ###### go through all primes in the list of all primes for j in range(number_of_primes): exponents_of_candidate.append(get_exponent_of_candidate_of_specific_prime(candidate,primes[j])); matrix_of_exponents.append(exponents_of_candidate); #print "matrix of all exponents" #print matrix_of_exponents return matrix(IntegerModRing(N),matrix_of_exponents); ################################################################ # NEED FOR: get_basis_of (via: get_matrix_of_exponents) ###### we assume that list_of_candidates is not empty def get_list_of_all_primes_in_increasing_order(list_of_candidates): ###### initialize primes=[]; ###### if the list of candidates in not empty if list_of_candidates != []: for j in range(len(list_of_candidates[0])): primes.append(list_of_candidates[0][j][0]); ###### now go through all other candidates number_of_candidates=len(list_of_candidates); for i in range(number_of_candidates-1): #print primes candidate=list_of_candidates[i+1]; number_of_primes_of_candidate=len(candidate); for j in range(number_of_primes_of_candidate): new_prime=candidate[j][0]; ###### join j-th prime in the list of primes at right position primes=join_prime_at_right_position(primes, new_prime); return primes; ################################################################ # NEED FOR: get_basis_of (via: get_matrix_of_exponents, get_list_of_all_primes_in_increasing_order) ###### we assume that list_of_primes is not an empty list def join_prime_at_right_position(list_of_primes, new_prime): returnvalue=list_of_primes; number_of_primes=len(list_of_primes); i=0; while i < number_of_primes: ###### if the prime is in the list, nothing to do; stop if new_prime==list_of_primes[i]: #print "primes identical" i=number_of_primes; else: ###### if new_prime is smaller that the one checking against put it in the list; then stop if new_prime<list_of_primes[i]: #print "prime smaller" returnvalue=[]; for j in range(number_of_primes+1): if j<i: returnvalue.append(list_of_primes[j]); else: if j==i: returnvalue.append(new_prime); else: returnvalue.append(list_of_primes[j-1]); i=number_of_primes; ###### if new_prime is bigger than the one checking against, go to next prime to check against else: #print "prime bigger" i=i+1; ###### if this was the last prime in the list, have to put prime at the end of the list if i==number_of_primes: returnvalue.append(new_prime); return returnvalue; ################################################################ # NEED FOR: get_basis_of (via: get_matrix_of_exponents) def get_exponent_of_candidate_of_specific_prime(candidate,prime): exponent=0; number_of_primes_to_check_against=len(candidate); i=0; while i < number_of_primes_to_check_against: ###### if primes agree, take its exponent and stop if prime==candidate[i][0]: exponent=candidate[i][1]; i=number_of_primes_to_check_against; i=i+1; return exponent; ############################################################################### #### METHODS FOR CALCULATING BASIS OF IMAGE OF COKER IN K* MOD FIFTH POWERS ############################################################################### ###### calculates the image of a point of coker in QQ(zeta_5)* def get_image_of_point_of_coker_in_QQ_zeta_5_star(P,i,j,a,K): sqrt_5=2*a^2+2*a^3+1; sqrt_x=2*a^3 + 6*a^2 + 8*a + 4; # x- and y-value of a generator of the dual kernel r_value=-1/2*(i^2+i*j+j^2) + sqrt_5/10*(i^2+11*i*j-j^2); t_value=1/4*(i^3+2*i^2*j+j^3) - sqrt_5/20*(i+j)*(i^2+11*i*j-j^2) + 1/20*(i^2+11*i*j-j^2)*(j/2*(11+5*sqrt_5)+i)*sqrt_x; # u and s value of the isogeny bringing E_dual into the form E_d, sending # the generator of the dual kernel to (0,0) s_value=(3*r_value^2+2*r_value*i*j-t_value*(i+j)+5*i^3*j-10*i^2*j^2-5*i*j^3)/(i*j^2+r_value*(i+j)+2*t_value); u_value=(i*j^2+r_value*(i+j)+2*t_value)/(i*j-s_value*(i+j)+3*r_value-s_value^2); #print("r_value"); print r_value; #print("t_value"); print t_value; #print("u_value"); print u_value; #print("s_value"); print s_value; x,y = PolynomialRing(K, 2, 'w').gens() #K_x=PolynomialRing(K, 'x,y'); # the isogeny is given by: (x,y) \mapsto ( (x-r_value)/u_value^2, (y-t_value-s_value*(x-r_value))/u_value^3 ) # the pullback (mod 5th powers) of this isogeny applied on -x^2+(x+1)*y is: # (habe einmal mit u_value^5 durchmultipliziert) phi_upper_star=-u_value*(x-r_value)^2+(x-r_value+u_value^2)*(y-t_value-s_value*(x-r_value)); #print phi_upper_star; z=phi_upper_star(P[0],P[1]); #print("z_value"); print z; return z; ###### image is a list of rational numbers. Returns a list of prime factorizations, whose exponents are reduced mod N def get_mod_N_reduced_non_trivial_images_as_a_list_in_prime_factors(K,a,unit_group_of_K,coker_unchecked, set_S_of_interesting_primes, ignore_units=0, N=5): reduced_image=[]; for i in range(0,len(coker_unchecked)): candidate=coker_unchecked[i]; #assume candidate is trivial (mod N-th powers), unless otherwise shown candidate_is_trivial=1; ideal_of_candidate=K.ideal(candidate); ##### get valuation wrt to the factorisation basis generators_of_prime_ideals # the list containing all the valuations of candidate wrt to prime_factorisation_in_K #(it saves a prime p, together with a list of exponents for the corresponding prime ideal # factorsiaztion stored in generators_of_prime_ideals_of_K valuation_of_candidate=[]; for k in range(0,len(set_S_of_interesting_primes)): # go through a factorization of the prime is_not_zero=false; exponent_for_prime=[]; for kk in range(0,len(generators_of_prime_ideals_of_K[set_S_of_interesting_primes[k]])): exponent=ideal_of_candidate.valuation(K.ideal(generators_of_prime_ideals_of_K[ set_S_of_interesting_primes[k]][kk])); candidate=candidate/generators_of_prime_ideals_of_K[set_S_of_interesting_primes[k]][kk]^exponent; exponent=exponent % N; exponent_for_prime.append(exponent); if exponent_for_prime[kk]!=0: is_not_zero=true; valuation_of_candidate.append([set_S_of_interesting_primes[k],exponent_for_prime]); if is_not_zero:candidate_is_trivial=0; #print("valuation mod units"); print valuation_of_candidate; #print("candidate"); print candidate; #print("candidate_is_trivial"); print candidate_is_trivial; #TODO: The factorization of ideal_of_candidate might take VERY LONG! if candidate_is_trivial+ignore_units!=2: #there might be other prime ideals left, but they should have exponent congruent 0 mod N # have to divide them out ideal_of_candidate=K.ideal(candidate); list_of_factorisation=list(ideal_of_candidate.factor()); #print("list_of_factorisation"); print list_of_factorisation; # make all exponents of prime factors of candidate having a value between 0 and 4 for k in range(0,len(list_of_factorisation)): if list_of_factorisation[k][1] % 5!=0: print("ERROR: in factorisation occured a prime different from the set S!"); n=(list_of_factorisation[k][1]-(list_of_factorisation[k][1] % 5))/5; generator=list_of_factorisation[k][0].gens_reduced()[0]; divisor=generator^(5*n); candidate=candidate/divisor; #print ("manipulated candidate"); print candidate #reduced_candidate_factorisation=list(K.ideal(candidate).factor()); #print ("list of manipulated candidate"); print reduced_candidate_factorisation; ###### get valuation of unit if candidate_is_trivial+ignore_units!=2: #print("unit_part_of_candidate"); print candidate; unit_valuation=unit_group_of_K.log(candidate); #print unit_valuation; # reduce unit valuation mod N is_not_zero=false; for k in range(0,2): unit_valuation[k]=unit_valuation[k]%N; if unit_valuation[k]!=0: is_not_zero=true; else: unit_valuation=[0,0] if is_not_zero:candidate_is_trivial=0; valuation_of_candidate.append([1,unit_valuation]); #print("reduced exponents of units"); print unit_valuation; ###### check if reduced image is non-trivial, and then apply if candidate_is_trivial==0: reduced_image.append(valuation_of_candidate); return reduced_image; ###### [ [ [11, [2, 3, 4, 1]] , [5, [0]] , [1, [3, 0]] ] ] ###### Image is a list of lists, where the inside lists corresponds to a generator of the image. ###### Each generator has as each entry a list which contains a prime number and then ###### a list with exponents that correspond to the prime ideal factorization wrt the saved basis. ###### Each generator should have the information for the same primes in the same order ###### Returns a subset of image with is a basis for the image def get_basis_of_mod_N_reduced_non_trivial_images(reduced_image, N=5): #print("get basis for"); print reduced_image; exponent_double_list=[]; basis_of_image=[]; #pick the first reduced_image as a basis element if len(reduced_image)>0: basis_of_image.append(reduced_image[0]); #init the first element, in case there are more than 1 elements if len(reduced_image)>1: exponents_of_generator=[]; # go over the primes of the first generator for kk in range(0,len(reduced_image[0])): # go over the exponents of the corresponding prime of the first generator for kkk in range(0,len(reduced_image[0][kk][1])): exponents_of_generator.append(reduced_image[0][kk][1][kkk]); exponent_double_list.append(exponents_of_generator); #print("exponent_double_list"); print exponent_double_list; #check every other reduced_image element if it is lin indep to the basis so far for i in range(1,len(reduced_image)): exponents_of_generator=[]; # go over the primes of the i-th generator for kk in range(0,len(reduced_image[i])): # go over the exponents of the corresponding prime of the i-th generator for kkk in range(0,len(reduced_image[i][kk][1])): exponents_of_generator.append(reduced_image[i][kk][1][kkk]); exponent_double_list.append(exponents_of_generator); matrix_of_exponents=matrix(IntegerModRing(N),exponent_double_list) # if the rank is the same as the number of elements, we found a lin indep generator if matrix_of_exponents.rank() == len(exponent_double_list): basis_of_image.append(reduced_image[i]); else: exponent_double_list.remove(exponents_of_generator); #print("basis is"); print basis_of_image; return basis_of_image; def exceptional(i,j): return 0; ########################################################################################## ########################################################################################## ########## METHODS FOR STEP2 ########################################################################################## ########################################################################################## def get_matrix_of_exponents_for_QQ_zeta_5_star(coker_unchecked, set_S_of_interesting_primes_1, set_S_of_interesting_primes_2,N=5): set_S_of_interesting_primes=list(union(set(set_S_of_interesting_primes_1),set(set_S_of_interesting_primes_2))); exponent_double_list=[]; #go through all generators of the cokernel for i in range(0, len(coker_unchecked)): exponents_of_generator=[]; # go over the primes S for kk in range(0,len(set_S_of_interesting_primes)): #init as the prime of S does not occur in the prime factorisation of the i-th generator found_prime=0; # go over the primes of the i-th generator for kkk in range(0,len(coker_unchecked[i])): # if the prime is the same as the prime of S if coker_unchecked[i][kkk][0]==set_S_of_interesting_primes[kk]: found_prime=1; #go over the exponents of that prime for kkkk in range(0,len(coker_unchecked[i][kkk][1])): exponents_of_generator.append(coker_unchecked[i][kkk][1][kkkk]); # if the prime was not in the list if found_prime==0: # add as many zeros as needed (one for each generator of the factorisation) for kkkk in range(0,len(generators_of_prime_ideals_of_K[set_S_of_interesting_primes[kk]])): exponents_of_generator.append(0); # add the exponents of the units position_of_units=len(coker_unchecked[i])-1; for kk in range(0,2): exponents_of_generator.append(coker_unchecked[i][position_of_units][1][kk]); # add the complete exponent list exponent_double_list.append(exponents_of_generator); #print("exponent_double_list"); print exponent_double_list; return matrix(IntegerModRing(N),exponent_double_list); ######################################### ### METHODS TO FILTER THE DATABASE ######################################### def cut_conductor(list_of_d, conductor_bound): returnvalue=[] for k in range(0,len(list_of_d)): if list_of_d[k][16]<=conductor_bound: returnvalue.append(list_of_d[k]) return returnvalue def cut_bound(list_of_d, bound): returnvalue=[] for k in range(0,len(list_of_d)): if list_of_d[k][0]<=bound and list_of_d[k][1]<=bound: returnvalue.append(list_of_d[k]) return returnvalue def cut_rank(list_of_d, rank_bound): returnvalue=[] for k in range(0,len(list_of_d)): if list_of_d[k][8]<=rank_bound: returnvalue.append(list_of_d[k]) return returnvalue def exact_rank(list_of_d, rank_exact): returnvalue=[] for k in range(0,len(list_of_d)): if list_of_d[k][8]==rank_exact: returnvalue.append(list_of_d[k]) return returnvalue def skip_rank(list_of_d, rank_skip): returnvalue=[] for k in range(0,len(list_of_d)): if list_of_d[k][8]!=rank_skip: returnvalue.append(list_of_d[k]) return returnvalue def get_good_sublist(list_of_d): returnvalue=[] for k in range(0,len(list_of_d)): # the conditions: # if rank and MWgens are known if list_of_d[k][8]!=-1 and (list_of_d[k][9]!=[] or list_of_d[k][8]==0): returnvalue.append(list_of_d[k]) return returnvalue ################################################### #### THE METHOD FOR STEP 2 WHICH TAKES A DATABASE, #### APPLIES SOME FILTERS ON IT, AND THEN CALCULATES #### THE DISTRIBUTION OF SQUARE AND NON-SQUARE SHA ################################################### def calculate_density(list_of_d, conductor_bound=0, bound=0, rank_bound=-1, rank_exact=-1, rank_skip=-1, different_rank=false): # filter the database if rank_exact!=-1: list_of_d=exact_rank(list_of_d, rank_exact); if rank_bound!=-1: list_of_d=cut_rank(list_of_d, rank_bound); if rank_skip!=-1: list_of_d=skip_rank(list_of_d, rank_skip); if bound!=0: list_of_d=cut_bound(list_of_d, bound); if conductor_bound!=0: list_of_d=cut_conductor(list_of_d, conductor_bound); original_length=len(list_of_d) original_number_of_surfaces=original_length*(original_length-1)/2; print('length of original list: '+str(original_length)) print('original_number_of_surfaces: '+str(original_number_of_surfaces)) list_of_d=get_good_sublist(list_of_d); total_number_of_curves=len(list_of_d); total_number_of_surfaces_to_calculate=total_number_of_curves*(total_number_of_curves-1)/2; print('total_number_of_curves: '+str(total_number_of_curves)) print('total_number_of_surfaces_to_calculate: '+str(total_number_of_surfaces_to_calculate)) # count the number of exponents appearing number_of_exponents_of_quotient=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; number_of_exponents_of_local_quotient=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; number_of_exponents_of_global_quotient=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; number_of_square_global_quotient_for_square_sha=0; number_of_non_square_global_quotient_for_square_sha=0; number_of_square_global_quotient_for_non_square_sha=0; number_of_non_square_global_quotient_for_non_square_sha=0; number_of_square_local_quotient_for_square_sha=0; number_of_non_square_local_quotient_for_square_sha=0; number_of_square_local_quotient_for_non_square_sha=0; number_of_non_square_local_quotient_for_non_square_sha=0; ################################################################################################## ##### Step 2: go through all pairs of elliptic curves ################################################################################################## number_of_calculated_surfaces=0; distribution=[0,0,0]; # counts square shas versus nonsquare shas (and the not considered ones) # run through all curves but the last one for i in range(0, total_number_of_curves-1): ##### run through all elliptic curves that are behind it in the list, ##### to run through all pairs of distinct elliptic curves #for j in range(i,i+1): for j in range(i+1,total_number_of_curves): # again some filtering if different_rank==false or (list_of_d[i][8]!=list_of_d[j][8]): #print intermediate results if number_of_calculated_surfaces% 10000==0 and number_of_calculated_surfaces>0: print("number_of_calculated_surfaces"); print number_of_calculated_surfaces; if distribution[1]+distribution[0]>0: print("intermediate results"); print(n(100*distribution[0]/(distribution[1]+distribution[0]))); number_of_calculated_surfaces=number_of_calculated_surfaces+1; ##### rename data of the two elliptic curves E1=list_of_d[i]; E2=list_of_d[j]; num_1=E1[0]; num_2=E2[0]; denom_1=E1[1]; denom_2=E2[1]; discr1_1=E1[2]; discr1_2=E2[2]; discr2_1=E1[3]; discr2_2=E2[3]; split_kernel_NOT_on_id_1=E1[4]; split_kernel_NOT_on_id_2=E2[4]; split_kernel_on_id_1=E1[5]; split_kernel_on_id_2=E2[5]; non_split_1=E1[6]; non_split_2=E2[6]; add_con_1=E1[7]; add_con_2=E2[7]; rank_1=E1[8]; rank_2=E2[8]; MWgenerators_1=E1[9]; MWgenerators_2=E2[9]; dual_MWgenerators_1=E1[10]; dual_MWgenerators_2=E2[10]; dual_coker_1=E1[11]; dual_coker_2=E2[11]; coker_1=E1[12]; coker_2=E2[12]; set_S_of_interesting_primes_1=E1[13]; set_S_of_interesting_primes_2=E2[13]; d_is_fifth_power_1=E1[14]; d_is_fifth_power_2=E2[14]; dim_coker_eta_1=E1[15]; dim_coker_eta_2=E2[15]; conductor_of_E_1=E1[16]; conductor_of_E_2=E2[16]; ########################### ##### Local Quotient ###### ########################### # the contribution of p=5 to the local quotient additive_contribution=0; if (add_con_1==2) and (add_con_2==2): additive_contribution=1; one_split_mult_NOT_on_id = union(set(split_kernel_NOT_on_id_1),set(split_kernel_NOT_on_id_2)); both_split_kernel_on_id = set(split_kernel_on_id_2).intersection(set(split_kernel_on_id_1)); # calculate the dimension of the local quotient # -1 from infinity # 1 from each prime where the kernel of the isogeny does not lie on the identity component # 1 from each prime where both curves have split mult. red, with the kernel on the identity component local_quotient =-1+additive_contribution-len(one_split_mult_NOT_on_id)+len(both_split_kernel_on_id); #statistics number_of_exponents_of_local_quotient[-local_quotient+3]= number_of_exponents_of_local_quotient[-local_quotient+3]+1; ###################################################### ########################### ##### Global Quotient ##### 1 + dim dual coker - dim coker (1 = dim ker - dim dual ker = 1 - 0 ) ########################### (dim coker = dim coker eta_1 + dim coker eta_2 - dim coker psi) dimension_dual_coker=0; dimension_coker_psi=0; if true: ########################## ##### dim dual coker ################## dual_coker_unchecked=[]; dual_coker_unchecked.extend(dual_coker_1); dual_coker_unchecked.extend(dual_coker_2); # only have to do something if the image is generated by more than one element if len(dual_coker_unchecked)>1: ###### order all occurring primes in increasing order and calculates the matrix of exponents ###### of the factorizations matrix_of_dual_exponents=get_matrix_of_exponents(dual_coker_unchecked, N=5); ###### the rank of this matrix is the dimension in question dimension_dual_coker=matrix_of_dual_exponents.rank(); #print("dimension of dual coker is");print dimension_dual_coker; else: dimension_dual_coker=len(dual_coker_unchecked); if true: ######################## ##### dim coker ######################## coker_unchecked=[]; coker_unchecked.extend(coker_1); coker_unchecked.extend(coker_2); #print("coker_unchecked is"); print coker_unchecked; # only have to do something if the image is generated by more than one element if len(coker_unchecked)>1: ###### a matrix wrt to the primefactorisation of S matrix_of_exponents=get_matrix_of_exponents_for_QQ_zeta_5_star(coker_unchecked, set_S_of_interesting_primes_1, set_S_of_interesting_primes_2, N=5); #print matrix_of_exponents; ###### the rank of this matrix is the dimension of coker psi dimension_coker_psi=matrix_of_exponents.rank(); #print("dimension of coker psi is");print dimension_coker_psi; #print("dimension of dim_coker_eta_1 is");print dim_coker_eta_1; #print("dimension of dim_coker_eta_2 is");print dim_coker_eta_2; else: dimension_coker_psi=len(coker_unchecked); # calculate the dimension of the global quotient global_quotient=1+dimension_dual_coker-dim_coker_eta_1-dim_coker_eta_2+dimension_coker_psi; #statistics number_of_exponents_of_global_quotient[global_quotient+3]= number_of_exponents_of_global_quotient[global_quotient+3]+1; #################################################################### ############################################## ##### summing up local and global quotient ############################################## #print local_quotient; #print("-----"); #print("global quotient"); print global_quotient; #print("rank"); print rank_1; #print("______"); #statistics number_of_exponents_of_quotient[3-(global_quotient+local_quotient)]= number_of_exponents_of_quotient[3-(global_quotient+local_quotient)]+1; # determine squareness (0=square, 1=non-square, 2=unknown) if true: m=(global_quotient+local_quotient)%2; else: m=2; distribution[m]=distribution[m]+1; #statistics #if sha is a square if m==0: if global_quotient%2==0: number_of_square_global_quotient_for_square_sha= number_of_square_global_quotient_for_square_sha+1; else: number_of_non_square_global_quotient_for_square_sha= number_of_non_square_global_quotient_for_square_sha+1; if local_quotient%2==0: number_of_square_local_quotient_for_square_sha= number_of_square_local_quotient_for_square_sha+1; else: number_of_non_square_local_quotient_for_square_sha= number_of_non_square_local_quotient_for_square_sha+1; # if sha is not a square if m==1: if global_quotient%2==0: number_of_square_global_quotient_for_non_square_sha= number_of_square_global_quotient_for_non_square_sha+1; else: number_of_non_square_global_quotient_for_non_square_sha= number_of_non_square_global_quotient_for_non_square_sha+1; if local_quotient%2==0: number_of_square_local_quotient_for_non_square_sha= number_of_square_local_quotient_for_non_square_sha+1; else: number_of_non_square_local_quotient_for_non_square_sha= number_of_non_square_local_quotient_for_non_square_sha+1; ######################### ##### End of Step 2 ##### ######################### print('------------------------------------------') print('length of original list: '+str(original_length)) print('original_number_of_surfaces: '+str(original_number_of_surfaces)) print('total_number_of_curves: '+str(total_number_of_curves)) print('total_number_of_surfaces_to_calculate: '+str(total_number_of_surfaces_to_calculate)) print("Total number of abelian surfaces with square or non-square Sha:"); distribution[2]=original_number_of_surfaces-total_number_of_surfaces_to_calculate print(distribution); print("Percentage of square Sha of modified list:"); if distribution[1]+distribution[0]>0: print [n(100*distribution[0]/(distribution[1]+distribution[0])), n(100*distribution[1]/(distribution[1]+distribution[0]))]; print("Percentage of distribution of unmodified list: square_min, square_max, non-square_min, non-square_max, unknown"); if distribution[1]+distribution[0]+distribution[2]>0: print [n(100*distribution[0]/(distribution[1]+distribution[0]+distribution[2])), n(100*(distribution[0]+distribution[2])/(distribution[1]+distribution[0]+distribution[2])), n(100*distribution[1]/(distribution[1]+distribution[0]+distribution[2])), n(100*(distribution[1]+distribution[2])/(distribution[1]+distribution[0]+distribution[2])), n(100*distribution[2]/(distribution[1]+distribution[0]+distribution[2]))]; print("number_of_exponents_of_local_quotient[-local_quotient+3]"); print number_of_exponents_of_local_quotient; print("number_of_exponents_of_global_quotient[global_quotient+3]"); print number_of_exponents_of_global_quotient; print("number_of_exponents_of_quotient[3-(global_quotient+local_quotient)]"); print number_of_exponents_of_quotient; print("number_of_square_global_quotient_for_square_sha"); print number_of_square_global_quotient_for_square_sha; print("number_of_non_square_global_quotient_for_square_sha"); print number_of_non_square_global_quotient_for_square_sha; print("number_of_square_global_quotient_for_non_square_sha"); print number_of_square_global_quotient_for_non_square_sha; print("number_of_non_square_global_quotient_for_non_square_sha"); print number_of_non_square_global_quotient_for_non_square_sha; #print("number_of_square_local_quotient_for_square_sha"); print number_of_square_local_quotient_for_square_sha; #print("number_of_non_square_local_quotient_for_square_sha"); print number_of_non_square_local_quotient_for_square_sha; #print("number_of_square_local_quotient_for_non_square_sha"); print number_of_square_local_quotient_for_non_square_sha; #print("number_of_non_square_local_quotient_for_non_square_sha"); print number_of_non_square_local_quotient_for_non_square_sha;
############################################################# ######## STEP 0 (CALCULATES GENERATORS OF PRIME IDEALS OF K) #############################################################
#### calculate once and for all generators of the prime ideal factorisation in K l=7; bound=200; old_bound=0; K.<a>=CyclotomicField(l); unit_group_of_K=UnitGroup(K); unit_generators_of_K=unit_group_of_K.gens(); generators_of_prime_ideals_of_K=[]; #generators_of_prime_ideals_of_K=load(DATA+"l="+str(l)+"_generators_of_prime_ideals_of_K_for_bound_200"); #print("LOADED"); if true: for k in range(0, 12*bound^2): #skip those which we already calculated if k>=12*old_bound^2: if Integer(k).is_prime(): factorisation=list(K.ideal(Integer(k)).factor()); fact_to_store=[]; #print factorisation; for kk in range(0,len(factorisation)): # add the first generator of the prime ideals to the factorisation basis fact_to_store.append(factorisation[kk][0].gens_reduced()[0]); generators_of_prime_ideals_of_K.append(fact_to_store); else: generators_of_prime_ideals_of_K.append(0); generators_of_prime_ideals_of_K[1]=unit_generators_of_K; save(generators_of_prime_ideals_of_K, DATA+"l="+str(l)+"_generators_of_prime_ideals_of_K_for_bound_200"); print("SAVED");
SAVED
## LOAD STEP 0 ########################################################## l=5; K.<a>=CyclotomicField(l); generators_of_prime_ideals_of_K=load(DATA+"l="+str(l)+"_generators_of_prime_ideals_of_K_for_bound_200"); print("LOADED")
LOADED
######################################################## ######### CREATING THE DATABASE (STEP 1) ########################################################
## LOAD EXISTING DATABASE ########################################################## l=5; loaded_list = load(DATA+"l="+str(l)+"_database_up_to_bound_30") print("LOADED")
LOADED
## FOR TESTING: ## CLEAR dual_MWgens AND image of coker IN DATABASE (KEEP rank AND MWgens) ############################################################ for k in range(0,len(loaded_list)): loaded_list[k][10]=[] loaded_list[k][11]=[] loaded_list[k][12]=[] loaded_list[k][15]=-1
## CREATES (OR EXTENDS) A DATABASE WITH EASY DATA OF ELLIPTIC CURVES (including conductor) ## The unknown data is: ## rank=-1; ## MWgenerators=[]; ## dual_MWgenerators=[]; ## basis_of_image_of_dual_coker=[]; ## basis_of_image_of_coker=[]; ## dim_coker_eta=-1; ################################################################# ## If lower_bound equals zero, a new database will be created. ## If this value is unequal to zero, sage expects that there is a ## database called "loaded_list". ## Creates all elliptic curves E_d, s.t. d=i/j, i and j coprime ## positive integers, and lower_bound< i,j <= bound. ################################################################## l=5; bound=30; lower_bound=0; if lower_bound==0: loaded_list=[] ##### go through all rational numbers with numerator and denominator bounded by the given bound for i in range(1,bound+1): # numerator for j in range(1,bound+1): # denominator if gcd(i,j)==1: # to check whether i/j was not treated before # check, if we have not already calculated the data if i>lower_bound or j>lower_bound: new_curve=get_basic_curve(i,j,l); loaded_list.append(new_curve);
##### ADD THE ANALYTIC RANK INTO A DATABASE, ##### which already knows the conductor. ##### Only calculates the rank if it is "unknown", i.e., rank=-1. ##### (if a bound is given, only curves of conductor less or equal to that conductor_bound ##### will be considered. conductor_bound=0 means no bound.) add_rank(loaded_list,l=7, conductor_bound=0)
Total number of elliptic curves: 16 print total_number_of_curves_with_rank_0 6 print total_number_of_curves_with_rank_1 9 print total_number_of_curves_with_rank_2 1 print total_number_of_curves_with_rank_3 0 print total_number_of_curves_with_rank_4 0 print total_number_of_curves_with_rank_5 0
## OPTIONAL: ## This is to prevent the next command to check again curves for which it already failed ########################################################################################### def exceptional(i,j): returnvalue=0; #height_limit=18 failed in the following cases: [i,j,rank,# found points] exc_curves=[[17, 23, 1, 0],[22, 17, 1, 0],[22, 23, 1, 0],[26, 29, 1, 0], [29, 23, 1, 0]] for k in range(0,len(exc_curves)): if i==exc_curves[k][0] and j==exc_curves[k][1]: returnvalue=1; return returnvalue;
##### ADD MW GENS IN A DATABASE (using height search with height_limit=18), ##### which already contains the rank. ##### Only considers curves for which the MW gens are "unknown", i.e., MWgenerators=[] and rank>0. ##### If a bound unequal to 0 is given, only curves E_d, ##### d=i/j, s.t. i,j<=bound will be considered. ############################################################################################################ ##### WARNING: It is not garanteed, that this will compute a MW-basis, ##### it rather produces a sublattice of finite index, s.t. the points are not div by 5 (mod torsion) ##### WARNING 2: Only if rank <=1, it is proven, that the sublattice has finite index, ##### otherwise we have to assume this, i.e., we assume that the analytic and MW-rank are equal. (BSD conjecture) ############################################################################################################ ##### MAY TAKE VERY LONG! (If bound >20) ############################################################################################################ add_gens_by_height_18(loaded_list, bound=0)
exceptional_curves []
##### ADD MW GENS IN A DATABASE (using MWgens), ##### which already contains the rank. ##### Only considers curves for which the MW gens are "unknown", i.e., MWgenerators=[] and rank>0. ##### If a bound unequal to 0 is given, only curves E_d, ##### d=i/j, s.t. i,j<=bound will be considered. ############################################################################################################ ##### MAY TAKE VERY LONG! ############################################################################################################ add_gens_by_MWgens(loaded_list, bound=0)
[26, 29, 1, [[-1296675666/8684809, -373134009194960/25594132123]]] [29, 23, 1, [[-41251717/337561, -1924994891742/196122941]]] exceptional_curves []
##### ADD DUAL MW GENERATORS, IMAGE OF DUAL COKER, AND DIM COKER ETA INTO A DATA BASE, ##### which already contains the rank and the MW generators. ################################################################################################ add_dual_gens(loaded_list)
##### ADD BASIS OF IMAGE OF COKER AS PRIME FACTORISATION OF QQ(zeta_5)* (mod fifth powers) ##### into a data base which knows the rank and dual_MWgenerators. ################################################################################################### ##### NEED STEP 0! ################################################################################################### unit_group_of_K=UnitGroup(K); add_image_of_coker(loaded_list)
try ignore_units=0 for [i,j,rank,d_is_fifth_power] [7, 1, 1, 0] exceptions []
##### SAVE LIST ############################################################## save(loaded_list, DATA+"database_up_to_bound_30"); print("SAVED");
SAVED
############################### ############################### ### STEP 2 ############################### ###############################
####################################################################### #### TAKE A DATABASE FROM STEP 1, APPLY SOME FILTERS ON IT, #### AND THEN CALCULATE THE DISTRIBUTION OF SQUARE AND NON-SQUARE SHA ####################################################################### #### NEED STEP 0. ####################################################################### calculate_density(loaded_list, conductor_bound=0, bound=0, rank_bound=-1, rank_exact=-1, rank_skip=-1, different_rank=false)
length of original list: 555 original_number_of_surfaces: 153735 total_number_of_curves: 555 total_number_of_surfaces_to_calculate: 153735 number_of_calculated_surfaces 10000 intermediate results 56.1500000000000 number_of_calculated_surfaces 20000 intermediate results 56.0500000000000 number_of_calculated_surfaces 30000 intermediate results 55.7233333333333 number_of_calculated_surfaces 40000 intermediate results 55.4975000000000 number_of_calculated_surfaces 50000 intermediate results 55.1760000000000 number_of_calculated_surfaces 60000 intermediate results 55.5016666666667 number_of_calculated_surfaces 70000 intermediate results 55.1457142857143 number_of_calculated_surfaces 80000 intermediate results 54.8250000000000 number_of_calculated_surfaces 90000 intermediate results 54.9266666666667 number_of_calculated_surfaces 100000 intermediate results 54.6290000000000 number_of_calculated_surfaces 110000 intermediate results 54.5345454545455 number_of_calculated_surfaces 120000 intermediate results 54.2858333333333 number_of_calculated_surfaces 130000 intermediate results 54.0607692307692 number_of_calculated_surfaces 140000 intermediate results 54.0078571428571 number_of_calculated_surfaces 150000 intermediate results 53.9500000000000 ------------------------------------------ length of original list: 555 original_number_of_surfaces: 153735 total_number_of_curves: 555 total_number_of_surfaces_to_calculate: 153735 Total number of abelian surfaces with square or non-square Sha: [83112, 70623, 0] Percentage of square Sha of modified list: [54.0618596936286, 45.9381403063714] Percentage of distribution of unmodified list: square_min, square_max, non-square_min, non-square_max, unknown [54.0618596936286, 54.0618596936286, 45.9381403063714, 45.9381403063714, 0.000000000000000] number_of_exponents_of_local_quotient[-local_quotient+3] [0, 0, 0, 0, 5, 200, 5403, 36061, 71767, 37277, 3022, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] number_of_exponents_of_global_quotient[global_quotient+3] [0, 0, 0, 0, 5, 795, 42648, 77708, 31017, 1556, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] number_of_exponents_of_quotient[3-(global_quotient+local_quotient)] [0, 0, 0, 46715, 62837, 36054, 7786, 343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] number_of_square_global_quotient_for_square_sha 41487 number_of_non_square_global_quotient_for_square_sha 41625 number_of_square_global_quotient_for_non_square_sha 38572 number_of_non_square_global_quotient_for_non_square_sha 32051
################################################################################## ################################################################################## ## EXTRA METHODS ################################################################################## ##################################################################################
## Analyses the calculated data of the database up to the given bound ## (bound==0 means: no bound) ######################################################################### def analyse_database(database,bound=0, conductor_bound=0): counter_curves=0 counter_unknown_rank=0 counter_known_rank=0 counter_known_rank_0=0 counter_known_rank_1=0 counter_known_rank_2=0 counter_known_rank_3=0 counter_known_rank_4=0 counter_known_rank_1_MW=0 counter_known_rank_2_MW=0 counter_known_rank_3_MW=0 counter_known_rank_4_MW=0 counter_unknown_MWgens=0 counter_unknown_MWgens_dual=0 counter_wrong_dim=0 counter_wrong_dim_sum=0 counter_d_is_fifth_power_rank_bigger_1=0 counter_d_is_fifth_power_rank_equal_1=0 counter_rank_bigger_2=0 #set_of_primes=set([5]) highest_prime=5 min_conductor_for_rank=[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]] max_conductor_for_rank=[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]] for k in range(0,len(database)): if (bound==0 or (database[k][0]<=bound and database[k][1]<=bound)) and (conductor_bound==0 or database[k][16]<=conductor_bound): counter_curves=counter_curves+1 #set_of_primes=union(set_of_primes,set(database[k][13])) for kk in database[k][13]: if kk>highest_prime: highest_prime=kk conductor=database[k][16]; rank=database[k][8]; if rank==-1: counter_unknown_rank=counter_unknown_rank+1 if conductor<min_conductor_for_rank[5][0] or min_conductor_for_rank[5][0]==0:min_conductor_for_rank[5][0]=conductor;min_conductor_for_rank[5][1]=database[k][0];min_conductor_for_rank[5][2]=database[k][1]; if conductor>max_conductor_for_rank[5][0]:max_conductor_for_rank[5][0]=conductor;max_conductor_for_rank[5][1]=database[k][0];max_conductor_for_rank[5][2]=database[k][1]; else: if rank>4: if conductor<min_conductor_for_rank[4][0] or min_conductor_for_rank[4][0]==0:min_conductor_for_rank[4][0]=conductor;min_conductor_for_rank[4][1]=database[k][0];min_conductor_for_rank[4][2]=database[k][1]; if conductor>max_conductor_for_rank[4][0]:max_conductor_for_rank[4][0]=conductor;max_conductor_for_rank[4][1]=database[k][0];max_conductor_for_rank[4][2]=database[k][1]; else: if conductor<min_conductor_for_rank[rank][0] or min_conductor_for_rank[rank][0]==0:min_conductor_for_rank[rank][0]=conductor;min_conductor_for_rank[rank][1]=database[k][0];min_conductor_for_rank[rank][2]=database[k][1]; if conductor>max_conductor_for_rank[rank][0]:max_conductor_for_rank[rank][0]=conductor;max_conductor_for_rank[rank][1]=database[k][0];max_conductor_for_rank[rank][2]=database[k][1]; counter_known_rank=counter_known_rank+1 if rank==0: counter_known_rank_0=counter_known_rank_0+1; elif rank==1: counter_known_rank_1=counter_known_rank_1+1; if database[k][9]!=[]: counter_known_rank_1_MW=counter_known_rank_1_MW+1; elif rank==2: counter_known_rank_2=counter_known_rank_2+1; if database[k][9]!=[]: counter_known_rank_2_MW=counter_known_rank_2_MW+1; elif rank==3: counter_known_rank_3=counter_known_rank_3+1; if database[k][9]!=[]: counter_known_rank_3_MW=counter_known_rank_3_MW+1; else: counter_known_rank_4=counter_known_rank_4+1; if database[k][9]!=[]: counter_known_rank_4_MW=counter_known_rank_4_MW+1; if database[k][8]>2: counter_rank_bigger_2=counter_rank_bigger_2+1 if database[k][14]==1 and database[k][8]>1: counter_d_is_fifth_power_rank_bigger_1=counter_d_is_fifth_power_rank_bigger_1+1 if database[k][14]==1 and database[k][8]==1: counter_d_is_fifth_power_rank_equal_1=counter_d_is_fifth_power_rank_equal_1+1 print [database[k][0],database[k][1],database[k][8],database[k][14]] if database[k][8]>0 and database[k][9]==[]: counter_unknown_MWgens=counter_unknown_MWgens+1 #print [database[k][0],database[k][1],database[k][8]] if database[k][8]>0 and database[k][10]==[] and database[k][9]!=[]: counter_unknown_MWgens_dual=counter_unknown_MWgens_dual+1 #print [database[k][0],database[k][1],database[k][8]] if database[k][15]!= len(database[k][12]) and (database[k][10]!=[] or database[k][8]==0): counter_wrong_dim=counter_wrong_dim+1 #print [database[k][0],database[k][1],database[k][8],database[k][9],database[k][10],database[k][12],database[k][15]] if database[k][15]+ len(database[k][11])!=database[k][8]+1: counter_wrong_dim_sum=counter_wrong_dim_sum+1 if (database[k][8]>0 and database[k][9]==[]) or (database[k][8]>0 and database[k][10]==[]) or (database[k][15]!= len(database[k][12]) or (database[k][15]+ len(database[k][11])!=database[k][8]+1) or (database[k][14]==1 and database[k][8]>1) or (database[k][8]>2)): pass #print [database[k][0],database[k][1],database[k][8],database[k][9],database[k][10],database[k][12],database[k][15]] if database[k][0]>2500 or database[k][1]>2500: print database[k] if bound==0 and conductor_bound==0: print('consider all curves in database') else: print ('only consider curves up to bound: '+str(bound)+' and up to conductor: '+str(conductor_bound)) #highest_prime=5 #for k in set_of_primes: # if k>highest_prime: # highest_prime=k print ('number of such curves: '+str(counter_curves)) print ('known rank: '+str(counter_known_rank)) print ('unknown rank: '+str(counter_unknown_rank)) print ('known rank 0: '+str(counter_known_rank_0)) print ('known rank 1: '+str(counter_known_rank_1)) print ('known rank 1 with known MWgens: '+str(counter_known_rank_1_MW)) print ('known rank 1 with unknown MWgens: '+str(counter_known_rank_1-counter_known_rank_1_MW)) print ('known rank 2: '+str(counter_known_rank_2)) print ('known rank 2 with known MWgens: '+str(counter_known_rank_2_MW)) print ('known rank 2 with unknown MWgens: '+str(counter_known_rank_2-counter_known_rank_2_MW)) print ('known rank 3: '+str(counter_known_rank_3)) print ('known rank 3 with known MWgens: '+str(counter_known_rank_3_MW)) print ('known rank 3 with unknown MWgens: '+str(counter_known_rank_3-counter_known_rank_3_MW)) print ('known rank 4: '+str(counter_known_rank_4)) print ('known rank 4 with known MWgens: '+str(counter_known_rank_4_MW)) print ('known rank 4 with unknown MWgens: '+str(counter_known_rank_4-counter_known_rank_4_MW)) print('----------') print ('unknown MW gens with known rank: '+str(counter_unknown_MWgens)) print ('unknown dual MW gens with known MW gens: '+str(counter_unknown_MWgens_dual)) print ('dim coker eta != dim of its image in K*/K*5, in case dual MW gens are known: '+str(counter_wrong_dim)) print ('dim coker eta + dim coker eta_dual != rank+1 : '+str(counter_wrong_dim_sum)) print ('d is fifth power and rank >=2 : '+str(counter_d_is_fifth_power_rank_bigger_1)) print ('d is fifth power and rank ==1 : '+str(counter_d_is_fifth_power_rank_equal_1)) print ('rank >=3 : '+str(counter_rank_bigger_2)) print ('highest prime occuring in all sets of intersting primes: '+str(highest_prime)) print('----------') highest_conductor=0; for k in range(0,6): if k<5: rank=k; else: rank='unknown'; print('min und max conductor for rank='+str(rank)+', [conductor,i,j]'); print min_conductor_for_rank[k] print max_conductor_for_rank[k] if max_conductor_for_rank[k]>highest_conductor: highest_conductor=max_conductor_for_rank[k]; print ('highest conductor occuring: '+str(highest_conductor));
## Analyses the calculated data of the database up to the given bound ## (bound=0 means: no bound) ######################################################################## analyse_database(loaded_list,bound=0,conductor_bound=0)
consider all curves in database number of such curves: 555 known rank: 555 unknown rank: 0 known rank 0: 245 known rank 1: 277 known rank 1 with known MWgens: 277 known rank 1 with unknown MWgens: 0 known rank 2: 33 known rank 2 with known MWgens: 33 known rank 2 with unknown MWgens: 0 known rank 3: 0 known rank 3 with known MWgens: 0 known rank 3 with unknown MWgens: 0 known rank 4: 0 known rank 4 with known MWgens: 0 known rank 4 with unknown MWgens: 0 ---------- unknown MW gens with known rank: 0 unknown dual MW gens with known MW gens: 0 dim coker eta != dim of its image in K*/K*5, in case dual MW gens are known: 0 dim coker eta + dim coker eta_dual != rank+1 : 0 d is fifth power and rank >=2 : 0 d is fifth power and rank ==1 : 0 rank >=3 : 0 highest prime occuring in all sets of intersting primes: 9629 ---------- min und max conductor for rank=0, [conductor,i,j] [11, 1, 1] [4685675, 23, 29] min und max conductor for rank=1, [conductor,i,j] [123, 3, 1] [8377230, 30, 29] min und max conductor for rank=2, [conductor,i,j] [5302, 1, 22] [8274570, 29, 30] min und max conductor for rank=3, [conductor,i,j] [0, 0, 0] [0, 0, 0] min und max conductor for rank=4, [conductor,i,j] [0, 0, 0] [0, 0, 0] min und max conductor for rank=unknown, [conductor,i,j] [0, 0, 0] [0, 0, 0] highest conductor occuring: [8377230, 30, 29]