def abc_xyz_simplified_with_gcd(prev_found_list, prev_total_cnt): new_list_no_reduced_1_1_2 =[] new_list_no_reduced_1_1_2_simplied = [] 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] # get gcd for three number, a, b, c abc_gcd = gcd_for_three_numbers(a, b, c) output_str, is_reduced_to_1_1_2 = simplify(a, x, b, y, c, z, abc_gcd, print_option = True) # recuded form, 1 + 1 = 2 is the most common format, let's skip this type of solutions if(is_reduced_to_1_1_2 == False): tmp_arr = deepcopy(find_item) # record the item new_list_no_reduced_1_1_2.append(tmp_arr) # also record the "simplified string format" new_list_no_reduced_1_1_2_simplied.append(output_str) new_total_cnt = len(new_list_no_reduced_1_1_2) print '==before remove reduced_1_1_2, prev_total_cnt = %10d, after: %10d ========================='%(prev_total_cnt, new_total_cnt) return new_list_no_reduced_1_1_2, new_list_no_reduced_1_1_2_simplied, new_total_cnt
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 simplify(a, x, b, y, c, z, abc_gcd, print_option = True): # 1 + 1 = 2 is the most common reduced format, we want to detect it is_reduced_to_1_1_2 = False # the following assertion is here because if it fail. It means that we find a solution # that its a, b, c are co-prime. assert (abc_gcd > 1) assert(a > 0) assert(b > 0) assert(c > 0) known_factor = abc_gcd # let's factor a^x = (u^v)*(r^s) ax_v, ax_r, ax_s = factor_power_of_num_with_known_factor(a, x, known_factor) by_v, by_r, by_s = factor_power_of_num_with_known_factor(b, y, known_factor) cz_v, cz_r, cz_s = factor_power_of_num_with_known_factor(c, z, known_factor) #print 'ax_v = %d, by_v = %d, cz_v = %d'%(ax_v, by_v, cz_v) # get the power of common factor for a^x, b^y, c^z common_factor_power = get_min(ax_v, by_v, cz_v) u = known_factor # after factoring out common_factor_power, u^common_factor_power, the remaining power factor of format u^?? for # a^x, b^y, c^z # For example, assume u = 2, a = (2^8)*(3^7), common_factor_power = 5, # then after factoring out 2^5 from a^x, b^y, c^z, a will have remaining format (2^3)*(3^7 where # ax_v_left = 3 ax_v_left = ax_v - common_factor_power by_v_left = by_v - common_factor_power cz_v_left = cz_v - common_factor_power assert(ax_v_left >= 0) assert(by_v_left >= 0) assert(cz_v_left >= 0) # print 'a = %4d, x = %4d, b = %4d, y = %4d, c = %4d, z = %4d'%(a, x, b, y, c, z) # print 'u = %d common_factor_power = %d, ax_v_left = %d, by_v_left = %d, cz_v_left = %d'%(u, common_factor_power, ax_v_left, by_v_left, cz_v_left) # after factoring out common factor power from a^x, b^y, c^z, # for remaining part of each number,, output as (u^v)*(r^s) format. # also try to detect if u or r == 1, or v and s == 0 ax_u_v_r_s_str, ax_result_type = format_u_v_r_s_output(u, ax_v_left, ax_r, ax_s) by_u_v_r_s_str, by_result_type = format_u_v_r_s_output(u, by_v_left, by_r, by_s) cz_u_v_r_s_str, cz_result_type = format_u_v_r_s_output(u, cz_v_left, cz_r, cz_s) a_x_b_y_c_z_str = '%d^%d + %d^%d = %d^%d'%(a, x, b, y, c, z) output_str = '%24s ==> %6s + %6s = %6s, u = %4d, cfp = %2d'%(a_x_b_y_c_z_str, ax_u_v_r_s_str, by_u_v_r_s_str, cz_u_v_r_s_str, u, common_factor_power) # if the following condition meet, maybe, we can simplify it again in a recursive way if( (ax_result_type == 1) or ( ax_result_type == 2 )) \ and ((by_result_type == 1) or ( by_result_type == 2 )) \ and ((cz_result_type == 1) or ( cz_result_type == 2)): # r^s for new a^x if(ax_result_type == 1): new_a = ax_r new_x = ax_s # u^v for new a^x if(ax_result_type == 2): new_a = u new_x = ax_v_left # r^s for new b^y if(by_result_type == 1): new_b = by_r new_y = by_s # u^v for new b^y if(by_result_type == 2): new_b = u new_y = by_v_left # r^s for new c^y if(cz_result_type == 1): new_c = cz_r new_z = cz_s # u^v for new c^y if(cz_result_type == 2): new_c = u new_z = cz_v_left new_gcd = gcd_for_three_numbers(new_a, new_b, new_c) if(new_gcd > 1): # the following is a recursive call, but will not print to screen output_str_again, is_reduced_to_1_1_2 = simplify(new_a, new_x, new_b, new_y, new_c, new_z, new_gcd, print_option = False) final_output_str = '%s --- %s '%(output_str, output_str_again) # this will not do recursive call else: final_output_str = '%s'%(output_str) # detect the most common reduced format: 1 + 1 = 2 if(ax_result_type == 0) and (by_result_type == 0): is_reduced_to_1_1_2 = True if(print_option == True): print final_output_str return final_output_str, is_reduced_to_1_1_2