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)
Exemple #2
0
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