def factor2(target): start_time = time() num_states = 0 if not isinstance(target, IntegerBaseFixed): target = IntegerBaseFixed(target) solved = False key_func = partial(product_to_hamming_distance, target=target) frontiers = defaultdict(lambda : BinarySearchTree(key_func)) # Find the maximum number of digits max_factor_num_digits = target_to_max_factor_num_digits(target, 0) for i, j in itertools.combinations_with_replacement(xrange(BASE), 2): prod = Product(i, j) frontiers[prod.factor_num_digits].insert(prod) num_states += 1 _iter = 0 while sum(map(len, frontiers.itervalues())): #for _iter in xrange(1000): _iter += 1 # Now queue the stuff we want to expand # First work out how many we want budget = 1000 dig_to_num_instances = {dig: len(tree) for dig, tree in frontiers.iteritems()} # Filter out zero instances # dig_to_num_instances = {dig: num for dig, num in dig_to_num_instances.iteritems() if num != 0} # And instances with too many digits # dig_to_num_instances = {dig: num for dig, num in dig_to_num_instances.iteritems() if dig < max_factor_num_digits} total_inst = sum(dig_to_num_instances.values()) if total_inst > budget: # Blind sweeper # dig_to_expand = sorted(dig_to_num_instances.keys())[_iter % len(dig_to_num_instances)] # dig_to_num_instances = {} # dig_to_num_instances[dig_to_expand] = budget # dig_to_num_instances = alloc_by_exp_weight(dig_to_num_instances, budget) # dig_to_num_instances = alloc_flat(dig_to_num_instances, 1) # dig_to_num_instances = alloc_exp_interp(dig_to_num_instances, 1, 5) dig_to_num_instances = alloc_exp_increasing(dig_to_num_instances, 1.3) # Shitty measure that's relative to how many instances there are of each digit. Prone to getting stuck #instances_per_iter = min(total_inst, desired_instances_to_expand) #dig_to_num_instances = {dig: int(num * instances_per_iter / total_inst) for dig, num in dig_to_num_instances.iteritems()} # Do some normalisation dig_to_num_instances = {dig: min(max(num, MIN_TO_EXPAND), len(frontiers[dig])) for dig, num in dig_to_num_instances.iteritems()} # Print out how we are allocating the budget if not _iter % 100 or 0: # sleep(0.2) print 'Num instances checked:', num_states print 'Solution location:' find_solution_root(frontiers, target) # # # keys = sorted(frontiers.keys()) # print 'Budget Allocation:' # for dig in keys[-5:]: # num_inst = len(frontiers[dig]) # if num_inst == 0: # continue # print dig, dig_to_num_instances.get(dig, 0), num_inst print #print dig_to_num_instances #print {dig: len(tree) for dig, tree in frontiers.iteritems()} #print # Now get them to_expand = [] for num_dig, num_inst in dig_to_num_instances.iteritems(): frontier = frontiers[num_dig] for _ in xrange(num_inst): to_expand.append(frontier.pop_min()) for candidate in to_expand: #print #print IntegerBaseFixed.from_int(target) #print candidate #from time import sleep #sleep(1) children = candidate.generate_children() children = filter_digit_length(children, min(max_factor_num_digits, target.num_digits)) children = filter_correct_digits(children, target) #children = filter_large_products(children, target) children = [child for child in children if child.as_int <= target.as_int] for child in children: if child.as_int == target.as_int: print 'Solution!', child solved = True break frontiers[child.factor_num_digits].insert(child) num_states += len(children) #print 'Checked:', num_states if solved: break end_time = time() print 'Iterations:', _iter print 'States checked:', num_states print 'Time taken: {:.2f}s'.format(end_time - start_time)
def analyse(target, error_func, max_states=100000): start_time = time() num_states = 0 if not isinstance(target, IntegerBase): target = IntegerBase(target) key_func = partial(error_func, target=target) frontiers = defaultdict(lambda : BinarySearchTree(key_func)) # Find the maximum number of digits max_factor_num_digits = target_to_max_factor_num_digits(target, 0) for i, j in itertools.combinations_with_replacement(xrange(BASE), 2): prod = Product(i, j) frontiers[prod.factor_num_digits].insert(prod) num_states += 1 solved = False _iter = 0 while 0 < sum(map(len, frontiers.itervalues())) < max_states: #for _iter in xrange(1000): _iter += 1 dig_to_num_instances = {dig: len(tree) for dig, tree in frontiers.iteritems()} find_solution_root(frontiers, target) # Now get them to_expand = [] for num_dig, num_inst in dig_to_num_instances.iteritems(): frontier = frontiers[num_dig] for _ in xrange(num_inst): to_add = frontier.pop_min() to_expand.append(to_add) for candidate in to_expand: #print #print IntegerBase.from_int(target) #print candidate #from time import sleep #sleep(1) children = candidate.generate_children() children = filter_digit_length(children, max_factor_num_digits) children = filter_correct_digits(children, target) #children = filter_large_products(children, target) #children = [child for child in children if child.as_int <= target.as_int] for child in children: if child.as_int == target.as_int: print 'Solution!', child solved = True break frontiers[child.factor_num_digits].insert(child) num_states += len(children) if solved: break end_time = time() # print 'Iterations:', _iter print 'States checked:', num_states # print 'Time taken: {:.2f}s'.format(end_time - start_time) print