def D_N_K_q_sum_over_k_1st(N, K, q, e_itkN_arr, gbc_con_expect, print_option = False): Shape = [q, q] main_term_l_l2_2d_arr = np.zeros(Shape, dtype = np.complex64) for l in range(1, q): if(l >= N): break gcd_l_q = gcd(l, q) if(gcd_l_q == 1): for l2 in range(1, q): if(l2 >= N): break gcd_l2_q = gcd(l2, q) if(gcd_l2_q == 1): for k in range(0, K): # sieg_walf will NOT be used when (q%K == 0) assert(q%K == 0) main_term_s_k_N_q_l, error_term_s_k_N_q_l = s_k_N_q_l(k, K, N, q, l) main_term_s_k_N_q_l2, error_term_s_k_N_q_l2 = s_k_N_q_l(k, K, N, q, l2) assert(main_term_s_k_N_q_l.real > error_term_s_k_N_q_l.real) assert(main_term_s_k_N_q_l2.real > error_term_s_k_N_q_l2.real) e_itkN = e_itkN_arr[k] main_term_l_l2 = e_itkN*main_term_s_k_N_q_l*main_term_s_k_N_q_l2 main_term_l_l2_2d_arr[l, l2] = main_term_l_l2
def co_prime_check(a, x, b, y, c, z): ab_gcd = gcd(a, b) ac_gcd = gcd(a, c) abc_gcd = gcd(ab_gcd, ac_gcd) if(abc_gcd == 1): print '!!! ============== co_prime_check: a = %4d, x = %4d, b = %4d, y = %4d, c = %4d, z = %4d'%(a, x, b, y, c, z) return abc_gcd
def s_k_N_q_sum_all_l(k, K, N, q, e_itkl_2d_arr): main_term_s_k_N_q_sum_all_l = 0 error_term_s_k_N_q_sum_all_l = 0 for l in range(1, q): if(l >= N): break gcd_l_q = gcd(l, q) if(gcd_l_q == 1): main_term_with_phase, main_term_no_phase, error_term_no_phase, error_term_with_phase = s_k_N_q_l(k, K, N, q, l, e_itkl_2d_arr) # main_term_sum need to be added with phase, so lots of cancellation can happen main_term_s_k_N_q_sum_all_l += main_term_with_phase # error_term_sum need to be added with no phase, so error will get larger and larger when more terms are include error_term_s_k_N_q_sum_all_l += error_term_no_phase # print " main_term_sum = ", main_term_sum, ", error_term_sum = ", error_term_sum # assert(main_term_s_k_N_q_sum_all_l > error_term_s_k_N_q_sum_all_l ) return main_term_s_k_N_q_sum_all_l, error_term_s_k_N_q_sum_all_l
def get_quadr_recip_using_multiplicative_properties(n, p, prime_list): check_p_is_prime = p in prime_list if(check_p_is_prime == False): print 'get_quadr_recip_using_multiplicative_properties only work for p is a prime, p %d'%(p) assert(0) if(gcd(n, p) >1): return 0 # first find reminder of m = n%p m = n%p # factor m into products of prime powers, and use multiplicative properties factor_list = factor_a_number(m, prime_list) tmp_qr = 1 count = len(factor_list) # using the multiplicative properties for x in range(count): # we can use either of the following methods to get (l | p) where l is a prime smaller than p # l = factor_list[x] # # We can further simplify the calculation by using quad_recip formula to reduce # (l | p) to (p | l) if NOT (l = 3 mod(4) and p = 3 mod(4)) # tmp2 = get_quadr_recip_brute_force(factor_list[x][0], p) # method 1 tmp2 = eul_criter(factor_list[x][0], p) # method 2 tmp3 = int(round(np.power(tmp2, factor_list[x][1] ))) tmp_qr *= tmp3 return tmp_qr
def get_major_ar(Q, t): MA =[] MA_a_q =[] for q in range(1, Q + 1): for a in range(q): if (gcd(a, q) == 1): I_q_a_t = get_I_q_a_t(q, a, t) tmp = deepcopy(I_q_a_t) MA.append(tmp) MA_a_q.append([a, q]) # sorted MA and return as 2D array MajorA_2d_arr = np.asarray(MA) MajorA_2d_sorted_arr = np.sort(MajorA_2d_arr, axis=0) # print MajorA_2d_sorted_arr # also output sorted [a, q] list, which shall be the fare_seq except the 1st one, which can be negative MajorA_2d_sorted_index_arr = np.argsort(MajorA_2d_arr, axis=0) print 'MajorA_2d_sorted_index_arr = ', MajorA_2d_sorted_index_arr MA_a_q_sorted_arr = [] cnt = len(MajorA_2d_sorted_index_arr) for i in range(cnt): MA_a_q_sorted_arr.append(MA_a_q[MajorA_2d_sorted_index_arr[i][0]]) print MA_a_q_sorted_arr return MajorA_2d_sorted_arr, MA_a_q_sorted_arr
def rama_sum_use_mobi_phi(n, m): a = gcd(n, m) N = n/a phi_n, coprime_list = eul_totie(n) phi_N, coprime_list = eul_totie(N) c_n_m = mobi_list[N - 1]*phi_n/phi_N return c_n_m
def rama_sum_use_prim_unit_root(q, m): c_q_m = 0 for h in range(1, q +1): gcd_h_q = gcd(h, q) if(gcd_h_q == 1): factor = 1j*2*np.pi*h*m/q c_q_m += np.exp(factor) return c_q_m
def get_quadr_recip_brute_force(n, p): if(gcd(n, p) >1): return 0 nRp_list = [] for x in range(p): if ((x*x - n)%p == 0): nRp_list.append(x) if(len(nRp_list ) > 0): return 1 else: return -1
def calculate_e_itkl_2d_arr(K, q): # if gcd(l, q) != 0, then e_itkl_2d_arr[k, l]= 0, # we need to check gcd(l, q) != 0 condition, to ensure that this function will not be called under # such condition. Shape = [K, q] e_itkl_2d_arr = np.zeros(Shape, dtype = np.complex64) theta = 2*np.pi/K for k in range(0, K): for l in range(1, q): gcd_l_q = gcd(l, q) if(gcd_l_q == 1): e_itkl_2d_arr[k, l] = np.exp(1j*theta*k*l) return e_itkl_2d_arr
def sum_of_product_for_orthog_property(m1, m2): # m = lcm(m1, m2) m = (m1*m2)/gcd(m1, m2) # print 'm = ', m sum = 0 for k in range(1, m+1): tmp1 = rama_sum_use_mobi(m1, k) # tmp1 = rama_sum_use_prim_unit_root(m1, k) tmp2 = rama_sum_use_mobi(m2, k) # tmp2 = rama_sum_use_prim_unit_root(m2, k) tmp= tmp1*tmp2 sum += tmp # print 'tmp1 = ', tmp1, ', tmp2 = ', tmp2, ', tmp = ', tmp sum = sum/float(m) return sum
def s_k_N_q_l(k, K, N, q, l, e_itkl_2d_arr, error_option = 1): # since this function is based on sieg_walf, so it requires assert(q%K == 0) assert(q%K == 0) # print "l = ", l assert(gcd(l, q) == 1) # phase e_itkl = e_itkl_2d_arr[k, l] phi_q, coprime_list = eul_totie(q) assert(phi_q > 0) # main term, N/(log(N)*phi(q)) main_term_no_phase = N/(np.log(N)*phi_q) # sieg_walf error term if(error_option == 1): # error term, N/(log(N)^2*phi(q)), with extra log(N) in denominator error_term_no_phase = N/(((np.log(N))**2)*phi_q) # GRH error term elif (error_option == 2): # error term, (np.sqrt(N)*np.log(N))/phi_q, with extra log(N) in numerator error_term_no_phase = (np.sqrt(N)*np.log(N))/phi_q # not support else: assert(0) main_term_with_phase = e_itkl* main_term_no_phase error_term_with_phase = e_itkl*error_term_no_phase # print " main_term_no_phase = ", main_term_no_phase, ", error_term_no_phase = ", error_term_no_phase assert(main_term_no_phase > error_term_no_phase) return main_term_with_phase, main_term_no_phase, error_term_no_phase, error_term_with_phase
def lamda_k(f_k_list, g_k_list, xi, mobi_list, k_range): lamda_k_list = [] # sum(u^2(m)/f(m) when 1 <= m <= xi sum_u_square_over_fm = 0 for m in range(1, xi): tmp = mobi_list[m - 1] * mobi_list[m - 1] / f_k_list[m - 1] sum_u_square_over_fm += tmp assert sum_u_square_over_fm != 0 for k in range(1, k_range + 1): # sum(u^2(m)/f(m) when 1 <= m <= xi/k and (m, k) = 1 sum_u_square_over_fm_mod_k = 0 xi_k = xi / k # when 1 <= m <= xi/k for m in range(1, xi_k): # (m, k) = 1 if gcd(m, k) == 1: tmp = mobi_list[m - 1] * mobi_list[m - 1] / f_k_list[m - 1] sum_u_square_over_fm_mod_k += tmp # u_k_over_f_k_g_k = u(k)/f(k)g(k) u_k_over_f_k_g_k = mobi_list[k - 1] / (f_k_list[k - 1] * g_k_list[k - 1]) # lamda_k lamda_k = u_k_over_f_k_g_k * sum_u_square_over_fm_mod_k / sum_u_square_over_fm lamda_k_list.append(lamda_k) return lamda_k_list
def verify_gaus_sum_of_char_prod(N, M): # this function only work for N, M are co-prime assert(gcd(N, M) == 1) ALMOST_ZERO = 0.001 # get dirich_char_mat, which is a 2D matrix dirich_char_mat_N, phi_n, coprime_list, prim_char_stat_all = dirichi_char_for_n(N) # get dirich_char_mat, which is a 2D matrix dirich_char_mat_M, phi_m, coprime_list, prim_char_stat_all = dirichi_char_for_n(M) # number of row. Note: 1st row is principle for i in range(0, phi_n): for j in range(0, phi_m): chi_i = dirich_char_mat_N[i] chi_j = dirich_char_mat_M[j] chi_i_chi_j = char_product(chi_i, chi_j) gaus_sum_chi_prod = gaus_sum_for_dirich_char(chi_i_chi_j) chi_i_M = chi_i[M%N] chi_j_N = chi_j[N%M] gaus_sum_chi_i = gaus_sum_for_dirich_char(chi_i) gaus_sum_chi_j = gaus_sum_for_dirich_char(chi_j) tmp = chi_i_M*chi_j_N*gaus_sum_chi_i*gaus_sum_chi_j assert(np.absolute(gaus_sum_chi_prod - tmp) < ALMOST_ZERO) # print 'chi = ', chi # print 'chi_conj = ', chi_conj # print 'N = %d, M = %d, i = %d, j = %d'%(N, M, i, j), ', gaus_sum_chi_prod = ', gaus_sum_chi_prod, ', tmp = ', tmp print 'verify_gaus_sum_of_char_prod() pass !'
def least_common_multiplier(k1, k2): lcm = (k1 * k2) / gcd(k1, k2) return lcm
def D_N_K_q_fixed_l(N, K, q, e_itkN_arr, e_itkl_2d_arr, gbc_con_expect_N_may_larger_than_K_fixed_l, print_option=False): main_term_for_D_N_q = 0 error_term_for_D_N_q = 0 # not consider phase factor, add error together error_term_with_phase_for_D_N_q = 0 # consider error with phase factor, will have cancellation is_q_good = 0 is_q_good_with_error_cancellation = 0 l1 = 1 l2 = (N - 1) % q assert gcd(l2, q) == 1 for k in range(0, K): # sieg_walf can NOT be used when (q%K != 0) assert q % K == 0 main_term_with_phase_l1, main_term_no_phase_l1, error_term_no_phase_l1, error_term_with_phase_l1 = s_k_N_q_l( k, K, N, q, l1, e_itkl_2d_arr ) main_term_with_phase_l2, main_term_no_phase_l2, error_term_no_phase_l2, error_term_with_phase_l2 = s_k_N_q_l( k, K, N, q, l2, e_itkl_2d_arr ) main_term_sum_square_k_N_q = main_term_with_phase_l1 * main_term_with_phase_l2 error_term_sum_square_k_N_q = ( main_term_no_phase_l1 * error_term_no_phase_l2 + main_term_no_phase_l2 * error_term_no_phase_l1 + error_term_no_phase_l1 * error_term_no_phase_l2 ) error_term_sum_square_with_phase_k_N_q = ( main_term_with_phase_l1 * error_term_with_phase_l2 + main_term_with_phase_l2 * error_term_with_phase_l1 + error_term_with_phase_l1 * error_term_with_phase_l2 ) # when sum over k, main_term needs to adjust with phase factor e_itkN = e_itkN_arr[k] main_term_for_D_N_q += e_itkN * main_term_sum_square_k_N_q # for error term, we calculate in two different methods, including phase factors or not including phase factors. # error_term_with_phase_for_D_N_q will be smallest error we can get theoretically, so it will be # the lower bound. It will be something that we can try to reach. error_term_for_D_N_q += error_term_sum_square_k_N_q error_term_with_phase_for_D_N_q += e_itkN * error_term_sum_square_with_phase_k_N_q if print_option: print "N = ", N, ", q = ", q, ", l1 = ", l1, ", l2 = ", l2, ", main_term_for_D_N_q/K = ", main_term_for_D_N_q / K, ", error_term_for_D_N_q/K = ", error_term_for_D_N_q / K, ", error_term_with_phase_for_D_N_q = ", error_term_with_phase_for_D_N_q / K, ", gbc_con_expect_N_may_larger_than_K_fixed_l = ", gbc_con_expect_N_may_larger_than_K_fixed_l if main_term_for_D_N_q.real > error_term_for_D_N_q: is_q_good = 1 if (main_term_for_D_N_q.real - error_term_for_D_N_q) > gbc_con_expect_N_may_larger_than_K_fixed_l: is_q_good = 2 if main_term_for_D_N_q.real > error_term_with_phase_for_D_N_q.real: is_q_good_with_error_cancellation = 1 if ( main_term_for_D_N_q.real - error_term_with_phase_for_D_N_q.real ) > gbc_con_expect_N_may_larger_than_K_fixed_l: is_q_good_with_error_cancellation = 2 return ( main_term_for_D_N_q / K, error_term_for_D_N_q / K, is_q_good, error_term_with_phase_for_D_N_q, is_q_good_with_error_cancellation, )
def D_N_K_search_K_for_fixed_N_q_l_for_N_list( q, N_list, only_search_1st_k=True, K_start=6, K_end=400, print_option=False ): print "D_N_K_search_K_for_fixed_N_q_l, K range(%d, %d), q = %d, tests start... " % (K_start, K_end, q) print "N_list = ", N_list N_K_good_list = [] skip_N_list = [] N_cnt = 0 N_K_good_cnt = 0 for N in N_list: # N only allow even number if N % 2 == 1: continue N_cnt += 1 # we will be only interested in the case that l2 is co-prime with q l2 = (N - 1) % q if gcd(l2, q) != 1: skip_N_list.append(N) continue gbc_con_expect = gbc_con_6_upto_target[(N - 6) / 2][1] for K in range(K_start, K_end): # because of sieg_walf, q must be the multiplier of K if q % K != 0: continue e_itkN_arr = calculate_e_itkN_arr(K, N) e_itkl_2d_arr = calculate_e_itkl_2d_arr(K, q) # get D_N_K_q_fixed_l() and D_N_K_counting_direct_fixed_l() main_term_for_D_N_q_K, error_term_for_D_N_q_K, is_N_K_good, error_term_with_phase_for_D_N_q, is_q_good_with_error_cancellation = D_N_K_q_fixed_l( N, K, q, e_itkN_arr, e_itkl_2d_arr, gbc_con_expect, print_option=False ) gbc_con_expect_N_may_larger_than_K_counting_direct_fixed_l = D_N_K_counting_direct_fixed_l( N, K, q, gbc_con_expect, l1=1, print_option=False ) if print_option: print "***** N = ", N, ", K = ", K, "q = ", q, ", main_term_for_D_N_q_K = ", main_term_for_D_N_q_K, ", gbc_con_expect_N_may_larger_than_K_counting_direct_fixed_l = ", gbc_con_expect_N_may_larger_than_K_counting_direct_fixed_l, ", gbc_con_expect = ", gbc_con_expect # we try to assert main_term_for_D_N_q_K.real <= gbc_con_expect_N_may_larger_than_K_counting_direct_fixed_l # but numerical round issues requires we loose the condition a bit. + 0.1 is needed in case that # gbc_con_expect_N_may_larger_than_K_counting_direct_fixed_l = 0 # assert(main_term_for_D_N_q_K.real <= 1.1*(gbc_con_expect_N_may_larger_than_K_counting_direct_fixed_l + 0.1)) if is_N_K_good > 0: N_K_good_list.append([N, K, q, main_term_for_D_N_q_K, error_term_for_D_N_q_K]) if only_search_1st_k == True: N_K_good_cnt += 1 break print "\nq = %d, l1 = 1, fixed: N_K_good_list.append([N, K, q, main_term_for_D_N_q_K, error_term_for_D_N_q_K]) = \n" % ( q ), np.asarray( N_K_good_list ) print "skip_N_list = ", skip_N_list failed_cnt = N_cnt - N_K_good_cnt - len(skip_N_list) print "N_cnt = %d, N_K_good_cnt %d, len(skip_N_list) = %d, failed_cnt = %d, q = %d" % ( N_cnt, N_K_good_cnt, len(skip_N_list), failed_cnt, q, ) print "D_N_K_search_K_for_fixed_N_q_l, K range(%d, %d), q = %d, fixed l1 = 1, done !" % (K_start, K_end, q) return N_cnt, N_K_good_cnt, skip_N_list, failed_cnt, N_K_good_list
def gbc_discre_for_N_K_Q_fixed_l(N, K, Q, l1=1): print "N = ", N, ", K = ", K, ", Q = ", Q e_itkN_arr = calculate_e_itkN_arr(K, N) print gbc_con_6_upto_target[(N - 6) / 2] gbc_con_expect = gbc_con_6_upto_target[(N - 6) / 2][1] assert gbc_con_6_upto_target[(N - 6) / 2][0] == N print "N = %d, gbc_con_expect = %d" % (N, gbc_con_expect) # q_good_list[] will hold a set of q ( 2 <= q <= Q) and q_good_list = [] q = Q # For easy counting, D_N_K_q_2d_arr include q = 0, q =1, which are always 0 # and it will go up to q (include q). Shape = [q + 1, 3] D_N_K_q_2d_arr = np.zeros(Shape, dtype=np.complex64) # record main term, error term, and gbc_con_expect_N_may_larger_than_K_fixed_l for every q with fixed l main_term_arr = np.zeros(q + 1, dtype=np.complex64) error_term_arr = np.zeros(q + 1, dtype=np.complex64) gbc_con_expect_N_may_larger_than_K_fixed_l_arr = np.zeros(q + 1, dtype=np.complex64) for q in range(2, Q + 1): l2 = (N - 1) % q # if (N-1)%q is not co-prime with q, this will make things complicated if we try to find out a good # model for it, let's skip such q for now. if gcd(l2, q) != 1: continue # sieg_walf can NOT be used when (q%K != 0) if q % K != 0: continue e_itkl_2d_arr = calculate_e_itkl_2d_arr(K, q) # get gbc_con directly by counting. This function allows N > K and N <= K gbc_con_expect_N_may_larger_than_K_fixed_l = D_N_K_counting_direct_fixed_l( N, K, q, gbc_con_expect, l1, print_option=False ) main_term_for_D_N_q, error_term_for_D_N_q, is_q_good, error_term_with_phase_for_D_N_q, is_q_good_with_error_cancellation = D_N_K_q_fixed_l( N, K, q, e_itkN_arr, e_itkl_2d_arr, gbc_con_expect_N_may_larger_than_K_fixed_l ) D_N_K_q_2d_arr[q][0] = main_term_for_D_N_q D_N_K_q_2d_arr[q][1] = error_term_for_D_N_q D_N_K_q_2d_arr[q][2] = is_q_good main_term_arr[q] = main_term_for_D_N_q error_term_arr[q] = error_term_for_D_N_q gbc_con_expect_N_may_larger_than_K_fixed_l_arr[q] = gbc_con_expect_N_may_larger_than_K_fixed_l if is_q_good > 0: q_good_list.append([q, main_term_for_D_N_q, error_term_for_D_N_q]) # plotting plt.figure() q_range = range(0, Q + 1) plot_one_list(main_term_arr.real, "main_term_arr.real", q_range, "ro-") plot_one_list(error_term_arr.real, "error_term_arr.real", q_range, "bx-") plot_one_list( gbc_con_expect_N_may_larger_than_K_fixed_l_arr.real, "gbc_con_expect_N_may_larger_than_K_fixed_l_arr.real", q_range, "gd-", ) title_str = ( "D_N_K_q_fixed_l: main: Red, error: blue, gbc_con_expect_fixed_l, green, gbc_con_expect = %d, N = %d, K = %d, Q = %d" % (gbc_con_expect, N, K, Q) ) plt.title(title_str) plt.xlabel("q range") plt.show(block=False)
def abc_xyz(n, ab_search_range_start = 2, ab_search_range_end = 10, xy_power_range_start = 2, xy_power_range_end = 10, only_co_prime = 0, x_same_y = 0, abc_odd_option = 0): found_list = [] find_item = [0]*6 total_loop_cnt = 0 global skip_cnt_for_c_not_include_all_prime_factors_of_a_b if (xy_power_range_start > min_power_3): min_power = xy_power_range_start else: min_power = min_power_3 for a in range(ab_search_range_start, ab_search_range_end): # if we are only interested in a, b, c are all odd if(abc_odd_option == 7) and (a%2 == 0): continue for x in range(min_power, xy_power_range_end): a_x = power_mod(a, x, n) # we only need to consider b>= a, # so that we will only count 3^3 + 6^3 = 3^5, not count # 6^3 + 3^3 = 3^5 for b in range(a, ab_search_range_end): # if we are only interested in a, b, c are all odd if(abc_odd_option == 7) and (b%2 == 0): continue # if we are interested in at least one of a, b is odd if(abc_odd_option == 1) and (a%2 == 0) and (b%2 != 1): continue ab_gcd = gcd(a, b) for y in range(min_power, xy_power_range_end): # if x_same_y flag is set, we will only handle the case y = x # In fact, it will be better if we just let y = x and not go into this # loop, but because y range is not much, so that will not be too much wasted. if(x_same_y == 1) and (y != x): continue b_y = power_mod(b, y, n) # need a better algorithm to find a range for c c_range = 6*(a + b) for c in range(2, c_range): # if we are only interested in a, b, c are all odd if(abc_odd_option == 7) and (c%2 == 0): continue # skip obvious no-solution case # if a, b has gcd factor (ab_gcd) which is larger than 1. # and ab_gcd has prime factor p1, p2, ..pr # then c must also contain those prime factors if(ab_gcd > 1): # Note: not sure if the following check will speed up program # because it involve factoring a number, which can be slow. # But if we have large z range, this will help. # Plus, it will also reduce the memory to save initial list. ret = check_c_contain_prime_factors_of_ab_gcd(ab_gcd, c) # c does not contain all prime factors of ab_gcd, # we need to skip this c. if (ret == 0): skip_cnt_for_c_not_include_all_prime_factors_of_a_b += 1 continue # if only check co_prime, then, we will skip those numbers # which are not co_primes if(only_co_prime == 1): abc_gcd = gcd_for_three_numbers(a, b, c) if(abc_gcd > 1): continue # it can happen that z_start > z_end in case z_end = 2 # in this case, we just skip the z loop z_start, z_end = get_range_for_z(a, x, b, y, c, min_power) for z in range(z_start, z_end): c_z = power_mod(c, z, n) tmp = a_x + b_y - c_z # found one, (tmp %n) == 0 is natural for mod(n) if((tmp %n) == 0): # do additional filtering, this will reduce memory usage # needed for initial list saving. if(additional_filtering(tmp, initial_mod)): print 'a = %4d, x = %4d, b = %4d, y = %4d, c = %4d, z = %4d'%(a, x, b, y, c, z) find_item[0]=a find_item[1]=x find_item[2]=b find_item[3]=y find_item[4]=c find_item[5]=z tmp_arr = deepcopy(find_item) found_list.append(tmp_arr) # found_list.append(find_item) total_loop_cnt += 1 total_cnt = len(found_list) print '================== n = %5d, total_cnt = %10d ========================='%(n, total_cnt) return found_list, total_cnt, total_loop_cnt
def check_jacob_symb_vs_quadr_recip(n, prime_list): print '=============== check_jacob_symb_vs_quadr_recip for up to n = %d'%(n) total_cnt = 0 # when jacob_symb is not proper indicator or quadr_recip. # We seperate them into type 1 or type 2 not_qr_indicator_type_1_cnt = 0 not_qr_indicator_type_2_cnt = 0 # only loop through odd integers, # because jacob_symb was only defined for odd prime number, not include 2 for p in xrange(3, n, 2): for q in range(3, n, 2): if(p == q): continue if(gcd(p, q) >1): continue jacob_p_q = jacob_sym(p, q, prime_list) jacob_q_p = jacob_sym(q, p, prime_list) total_cnt += 1 # brute force way to check quard_recip qr_bf_p_q = get_quadr_recip_brute_force(p, q) qr_bf_q_p = get_quadr_recip_brute_force(q, p) tmp = p_1_q_1_divide_by_4(p, q) if(tmp%2 == 0): right_side = 1 else: right_side = -1 # assert (p|q)(q|p) == (-1)^((p-1)*(q - 1)/4) assert(right_side == jacob_p_q*jacob_q_p) # Note 1: For jacob, it could happen that jacob(q|n) == 1, while q is not quadr_recip of n, when n is composite number. # Note 2: For jacob, if quadr_recip = 1, jacob(q | n) must be 1 # if quadr_recip = -1, jacob(q | n) can be 1 or -1 # if jacob(q | n) = 1, quadr_recip can be 1 or -1 # if jacob(q | n) = -1, quadr_recip must -1 if( qr_bf_p_q == 1): assert(jacob_p_q == 1) if( jacob_p_q == -1): assert(qr_bf_p_q == -1) # if qr_bf_p_q == -1, but jacob_p_q = 1, which means jacob_symp not an indicator of quadr_recip if(qr_bf_p_q == -1): if(jacob_p_q != -1): not_qr_indicator_type_1_cnt += 1 # print ' : p = %d, q = %d, qr_bf_p_q = %d, jacob_p_q = %d'%(p, q, qr_bf_p_q, jacob_p_q) # if jacob_p_q == 1, but qr_bf_p_q = -1, which means jacob_symp not an indicator of quadr_recip if(jacob_p_q == 1): if(qr_bf_p_q != 1): not_qr_indicator_type_2_cnt += 1 # print ' : p = %d, q = %d, qr_bf_p_q = %d, jacob_p_q = %d'%(p, q, qr_bf_p_q, jacob_p_q) not_qr_indicator_cnt = not_qr_indicator_type_1_cnt + not_qr_indicator_type_2_cnt not_qr_indictor_ratio = float(not_qr_indicator_cnt)/total_cnt print 'check_jacob_symb_vs_quadr_recip, n = ', n, ', total_cnt = ', total_cnt, ', not_qr_indicator_type_1_cnt = ', not_qr_indicator_type_1_cnt, ',not_qr_indicator_type_2_cnt = ',not_qr_indicator_type_2_cnt print 'check_jacob_symb_vs_quadr_recip, n = ', n, ', not_qr_indictor_ratio = ', not_qr_indictor_ratio return not_qr_indictor_ratio