def abc_xyz_recur(n, prev_found_list, prev_total_cnt, new_found_list): # this function shall not be called if prev_total_cnt is zero assert(prev_total_cnt > 0) # j will be used to hold item in new found_list j = 0 for i in range(prev_total_cnt): find_item = prev_found_list[i] a = find_item[0] x = find_item[1] b = find_item[2] y = find_item[3] c = find_item[4] z = find_item[5] a_x = power_mod(a, x, n) b_y = power_mod(b, y, n) c_z = power_mod(c, z, n) tmp = a_x + b_y - c_z # found one which congruence to n if((tmp %n) == 0): print 'a = %4d, x = %4d, b = %4d, y = %4d, c = %4d, z = %4d'%(a, x, b, y, c, z) new_found_list[j][0]=a new_found_list[j][1]=x new_found_list[j][2]=b new_found_list[j][3]=y new_found_list[j][4]=c new_found_list[j][5]=z # move to next j += 1 # write the next line after the final line as watermark line, put some junk here. # this is ued to detect programming errors new_found_list[j][0]= -1 new_found_list[j][1]= -1 new_found_list[j][2]= -1 new_found_list[j][3]= -1 new_found_list[j][4]= -1 new_found_list[j][5]= -1 new_total_cnt = j print '======================== n = %5d, prev_total_cnt = %10d, new_total_cnt = %10d====================='%(n, prev_total_cnt, new_total_cnt) changed_flag = 0 if(new_total_cnt != prev_total_cnt): changed_flag = 1 return new_total_cnt, changed_flag
def prim_roots(n, smllest_only = True): phi_i, coprime_list = eul_totie(n) prim_root_list = [] # coprime_list include 1 as first element, skip it for g in coprime_list[1:]: for i in range(2, (phi_i + 1)): # g_power_i = int(round(np.power(g, i))) # g_power_i_mod_n = g_power_i%n g_power_i_mod_n = power_mod(g, i, n) if(g_power_i_mod_n == 1): # break i loop and go to another number if (i < phi_i): break # break i loop if (i == phi_i): prim_root_list.append(g) # print 'prim_root_list: n = ', n, ' g = ', g, ' i = ', i, ' g_power_i = ', g_power_i, ' g_power_i_mod_n = ', g_power_i_mod_n break # if only want to find smallest option is on, break the loop if we find one if(smllest_only == True): # if find smallest prim_root, break the loop if (len(prim_root_list) != 0): break return prim_root_list
def eul_criter(n, p): i = (p - 1)/2 n_p = power_mod(n, i, p) # power_mod(...) may return any number between 0, to p-1. For p-1, we want to return -1 instead of p-1 if(n_p > 1): n_p = n_p - p return n_p
def get_bn(n, l): bn_found = -1 if(n%2 == 0): print 'get_bn only works for odd number' return bn_found if(l <= 2): print 'get_bn only works for l >= 3' return bn_found p_power_l = int(round(np.power(2, l))) # print 'l = ', l, ', p_power_l = ', p_power_l phi_p_l, coprime_list = eul_totie(p_power_l) up_bound = (phi_p_l)/2 bn_found_cnt = 0 for bn in range(1, up_bound + 1): tmp1 = int(round(np.power(-1, (n-1)/2))) tmp2 = power_mod(5, bn, p_power_l) tmp = tmp1*tmp2 if((n - tmp)%(p_power_l) == 0): bn_found = bn bn_found_cnt += 1 # if we do not break from here, we can check if the solution is unique # It turns out that solution is indeed unique break if (bn_found == -1): print 'get_bn fail for n ', n, ', l = ', l, ', p_power_l = ', p_power_l # according to theorem, this should never happen assert(0) # solution must be unique assert(bn_found_cnt == 1) # print 'get_bn: n ', n, ', l = ', l, ' bn = ', bn return bn_found
def indice_g_n(a, g, n): phi_n, coprime_list = eul_totie(n) indice = -1 # if a is NOT co-prime with n, if ((a in coprime_list ) == False): return indice for i in range(phi_n): b = power_mod(g, i, n) if(a%n == b): indice = i break return indice
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 abc_fixed_xyz(n, a, b, c, xy_power_range_start = 2, xy_power_range_end = 10, x_same_y = 0): found_list = [] find_item = [0]*6 total_loop_cnt = 0 if (xy_power_range_start > min_power_3): min_power = xy_power_range_start else: min_power = min_power_3 for x in range(min_power, xy_power_range_end): # print 'x = %d'%(x) a_x = power_mod(a, x, n) 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) # 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