Suggestions to optimise brute force number solver python - python

I'm aware of a few other similar threads, but im not sure how to apply them to my example.
I am trying to attack the countdown number game from a brute force algorithm. This is my first attempt at anything like this, so any tips on how to speed up the process up?
I am testing it for situations where the answer is unsolvable given the initial numbers. This eventually will be paired up with a tkinter interface for the full game.
structure should look like this, where we try every order of abcdef and every operation combo for op1-5
from datetime import datetime
import itertools
import math
starttime = datetime.now()
def permutationG(input, s):
if len(s) == len(input): yield s
for i in input:
if i in s: continue
s=s+i
for x in permutationG(input, s): yield x
s=s[:-1]
def op(operator, number1,number2):
string=str(number1)+str(operator)+str(number2)
return eval(string)
a=11
b=10
c=9
d=8
e=7
f=6
targetnumber = 101234
listofnumbers = ['a','b','c','d','e','f']
listprep = ['+','-','*','/']
stringofnumbers = ''.join(str(e) for e in listofnumbers)
numberlocations =[]
for item in permutationG(listofnumbers,''):
numberlocations.append(item)
numberlocations = set(numberlocations)
myarray = itertools.combinations_with_replacement(listprep, 5)
operatorlist = []
for item in myarray:
#for all different numbers find the different permutations
temp = list(itertools.permutations(item))
operatorlist.extend(temp)
#remove duplicates
finaloplist = list(set(operatorlist))
dist=[math.inf]
currentclosestnumber = 0
count=0
looptime=datetime.now()
print('Starting Loop')
for item in numberlocations:
for ops in finaloplist:
initial_value = op(ops[0],item[0],item[1])
for i in range(2,len(item)):
intcheck2 = int(initial_value) - initial_value
if initial_value != targetnumber and initial_value >= 0 and intcheck2 == 0:
newvalue = op(ops[i-1], initial_value, item[i])
else:
break
initial_value = newvalue
attempt = initial_value
intcheck = int(attempt) - attempt
distance = targetnumber - initial_value
if abs(distance) < abs(dist[0]) and intcheck == 0:
currentclosestnumber = attempt
dist[0]=distance
print(attempt)
if targetnumber == attempt:
break
if targetnumber == attempt:
break
endtime = datetime.now()
stringtime= endtime-starttime
#print('Loops: ', count)
if targetnumber == attempt:
print('FOUNDIT!! Target Number = %s Closest Number = %s Time Elapsed = %s' %(targetnumber, currentclosestnumber, stringtime))
elif targetnumber!=attempt:
print('Heres how close: Target Number = %s Closest Number = %s Time Elapsed = %s' %(targetnumber, currentclosestnumber, stringtime))
This outputs a time of roughly a minute and a half.
Another issue is because of the method I'm using (using eval string manipulation) I have no idea to show where the brackets go in the final formula when printed, or how to fit an eval into the zip at the end to show the numbers instead of the letters.
Any guidance is really appreciated.
Note: I have edited the post with the most recent version of the code. This reduced the time to calculate from 1:30 to 0:45. The major change was instead of one long string of calculations I created a for loop for each sequential operation, with an if statement to make sure that if the current value is negative or a decimal it breaks.
This reduces the number of calculations required significantly.

Here is a slower version but without the bugs.
I don't have time to try to optimize, but my thought is that most of the problem is in creating/destroying garbage in splitting subsets.
If I really wanted this to be fast, I think that you could use a dynamic programming approach.
def subset_splits (a_list):
if 0 == len(a_list):
yield ([], [])
else:
for sublist1, sublist2 in subset_splits(a_list[1:]):
yield ([a_list[0]] + sublist1, sublist2)
yield ([a_list[0]] + sublist2, sublist1)
def reachable (numbers):
if 1 == len(numbers):
yield (numbers[0], numbers[0])
else:
for list1, list2 in subset_splits(numbers):
if 0 == len(list2):
continue
for x1, expr1 in reachable(list1):
for x2, expr2 in reachable(list2):
yield x1+x2, (expr1, '+', expr2)
yield x1*x2, (expr1, '*', expr2)
yield x1-x2, (expr1, '-', expr2)
yield x2-x1, (expr2, '-', expr1)
if 0 != x2:
yield x1/x2, (expr1, '/', expr2)
if 0 != x1:
yield x2/x1, (expr2, '/', expr1)
numbers = [1, 2, 3, 4, 5, 6]
target = 10000
best = numbers[0]
if best == target:
print(("Answer: ", numbers[0], numbers[0]))
else:
print(("Best: ", numbers[0], numbers[0]))
done = False;
for s, t in subset_splits(numbers):
if done:
break
for x, expr in reachable(s):
if x == target:
print(("Answer: ", x, expr))
done = True
break
elif abs(target-x) < abs(target-best):
print(("Best: ", x, expr))
best = x
if done:
break
for x, expr in reachable(t):
if x == target:
print(("Answer: ", x, expr))
done = True
break
elif abs(target-x) < abs(best-x):
print(("Best: ", x, expr))
best = x

Related

Rolling a roulette with chances and counting the maximum same-side sequences of a number of rolls

I am trying to generate a random sequence of numbers, with each "result" having a chance of {a}48.6%/{b}48.6%/{c}2.8%.
Counting how many times in a sequence of 6 or more {a} occurred, same for {b}.
{c} counts as neutral, meaning that if an {a} sequence is happening, {c} will count as {a}, additionally if a {b} sequence is happening, then {c} will count as {b}.
The thing is that the results seem right, but every "i" iteration seems to give results that are "weighted" either on the {a} side or the {b} side. And I can't seem to figure out why.
I would expect for example to have a result of :
{a:6, b:7, a:8, a:7, b:9} but what I am getting is {a:7, a:9, a:6, a:8} OR {b:7, b:8, b:6} etc.
Any ideas?
import sys
import random
from random import seed
from random import randint
from datetime import datetime
import time
loopRange = 8
flips = 500
median = 0
for j in range(loopRange):
random.seed(datetime.now())
sequenceArray = []
maxN = 0
flag1 = -1
flag2 = -1
for i in range(flips):
number = randint(1, 1000)
if(number <= 486):
flag1 = 0
sequenceArray.append(number)
elif(number > 486 and number <= 972):
flag1 = 1
sequenceArray.append(number)
elif(number > 972):
sequenceArray.append(number)
if(flag1 != -1 and flag2 == -1):
flag2 = flag1
if(flag1 != flag2):
sequenceArray.pop()
if(len(sequenceArray) > maxN):
maxN = len(sequenceArray)
if(len(sequenceArray) >= 6):
print(len(sequenceArray))
# print(sequenceArray)
# print(sequenceArray)
sequenceArray = []
median += maxN
print("Maximum sequence is %d " % maxN)
print("\n")
time.sleep(random.uniform(0.1, 1))
median = float(median/loopRange)
print("\n")
print(median)
I would implement something with two cursors prev (previous) and curr (current) since you need to detect a change between the current and the previous state.
I just write the code of the inner loop on i since the external loop adds complexity without focusing on the source of the problem. You can then include this in your piece of code. It seems to work for me, but I am not sure to understand perfectly how you want to manage all the behaviours (especially at start).
prev = -1
curr = -1
seq = []
maxN = 0
for i in range(flips):
number = randint(1, 1000)
if number<=486:
curr = 0 # case 'a'
elif number<=972:
curr = 1 # case 'b'
else:
curr = 2 # case 'c', the joker
if (prev==-1) and (curr==2):
# If we start with the joker, don't do anything
# You can add code here to change this behavior
pass
else:
if (prev==-1):
# At start, it is like the previous element is the current one
prev=curr
if (prev==curr) or (curr==2):
# We continue the sequence
seq.append(number)
else:
# Break the sequence
maxN = max(maxN,len(seq)) # save maximum length
if len(seq)>=6:
print("%u: %r"%(prev,seq))
seq = [] # reset sequence
seq.append(number) # don't forget to append the new number! It breaks the sequence, but starts a new one
prev=curr # We switch case 'a' for 'b', or 'b' for 'a'

Traveling Salesman with GA, mutation, crossover

For school last semester, I wrote a python program to solve the traveling salesman problem. For those not familiar with what it is, the wolfram alpha explanation does a pretty good job of explaining it.
This was one of the first programs I wrote in Python, and so far I LOVE the language, coming from a C++/Java background. Anyway, I used a lot of inefficient methods/programming practices to get it working, so I wanted to go back and improve. I used a genetic algorithm with mutations and ordered crossovers. First, I create a list of random unique nodes with a given length and a given number of strategies. The GA runs through a given number of generations of these strategies, changing a random selection of strategies by using ordered crossover and an inverse mutation between two random indices. Each strategy has a given probability of a mutation and another probability of crossover. After this, the algorithm chooses two strategies at random, takes the best one, then compares it to the best solution found so far. The end goal of the program is to find the shortest distance through all the nodes.
Here is my original, inefficient, working code
Here is my newer, efficient, not working code:
import random
import math
import pprint
from matplotlib import pyplot as plt
def create_nodes(num_nodes, num_rows):
elements = range(1, num_nodes + 1)
return [random.sample(elements, num_nodes) for _ in range(num_rows)]
def mutate(table, node_table, mutate_probability, cross_probability):
for next_id, row in enumerate(table, 1):
nodes = len(row)
# print
# print "Original: ", row
#mutation
if random.random() > mutate_probability:
mini, maxi = sorted(random.sample(range(nodes),2))
row[mini:maxi+1] = row[mini:maxi+1][::-1]
# print "After mutation: ", row
# print "Between: ", mini, maxi
#crossover
if random.random() > cross_probability:
try:
next_row = table[next_id]
# print "Parent: ", next_row
except IndexError:
pass
else:
half_length = nodes//2
mini = random.randint(0, half_length)
maxi = mini + half_length - 1 + (nodes % 2)
crossed = [None] * nodes
# print "Before crossed: ", row
crossed[mini:maxi+1] = next_row[mini:maxi+1]
# print "Cross with: ", crossed
iterator = 0
for element in row:
if element in crossed:
continue
while mini <= iterator <= maxi:
iterator += 1
crossed[iterator] = element
iterator += 1
row[:] = crossed
# print "After crossed: ", row
# print "Between: ", mini, maxi
def sample_best(table, node_table):
t1, t2 = random.sample(table[1:], 2)
return distance(t1, t2, node_table)
def distance(s1, s2, node_table):
distance1 = sum_distances(s1, node_table)
distance2 = sum_distances(s2, node_table)
if distance1 < distance2:
return s1, distance1
else:
return s2, distance2
def sum_distances(strategy, node_table):
dist = 0
first_row, second_row = node_table
for idx_next_node, node1 in enumerate(strategy, 1):
try:
node2 = strategy[idx_next_node]
except IndexError:
node2 = strategy[0]
dist += math.hypot(
first_row[node2-1] - first_row[node1-1],
second_row[node2-1] - second_row[node1-1])
return dist
def draw_graph(node_table, strategy):
graphX = [node_table[0][index - 1] for index in strategy]
graphY = [node_table[1][index - 1] for index in strategy]
plt.scatter(graphX, graphY)
plt.plot(graphX, graphY)
plt.show()
def main(nodes=8, strategies=100, generations=10000, mutateP=.7, crossP=.7):
#create node locations
node_table = create_nodes(nodes, 2)
# for i in range(2):
# print node_table[i]
#create first generation
table = create_nodes(nodes, strategies)
# for i in range(strategies):
# print i
# print table[i]
print "TOP MEN are looking through:"
print strategies, "strategies in", generations, "generations with",
print nodes, "nodes in each strategy..."
best_score = None
for count in range(generations):
mutate(table, node_table, mutateP, crossP)
# crossover(table, node_table, crossP)
strategy, score = sample_best(table, node_table)
if best_score is None or score < best_score:
best_strategy = strategy
best_score = score
if count % 100 == 0:
print "Foraged", count, "berries"
print "Best we got so far:", best_score, "with: ", best_strategy
# if count % 2 == 0:
# print count
# for i in range(strategies):
# print table[i]
print "=========================================================================="
print "Best we could find: ", best_score, "for strategy", best_strategy
draw_graph(node_table, best_strategy)
main()
The new code is what I'm having trouble with. The mutation and crossover seem to be working correctly, but the algorithm isn't even coming close to finding a solution and I have no idea why. Thanks for the help in advance, I really appreciate it!

Generate equation with the result value closest to the requested one, have speed problems

I am writing some quiz game and need computer to solve 1 game in the quiz if players fail to solve it.
Given data :
List of 6 numbers to use, for example 4, 8, 6, 2, 15, 50.
Targeted value, where 0 < value < 1000, for example 590.
Available operations are division, addition, multiplication and division.
Parentheses can be used.
Generate mathematical expression which evaluation is equal, or as close as possible, to the target value. For example for numbers given above, expression could be : (6 + 4) * 50 + 15 * (8 - 2) = 590
My algorithm is as follows :
Generate all permutations of all the subsets of the given numbers from (1) above
For each permutation generate all parenthesis and operator combinations
Track the closest value as algorithm runs
I can not think of any smart optimization to the brute-force algorithm above, which will speed it up by the order of magnitude. Also I must optimize for the worst case, because many quiz games will be run simultaneously on the server.
Code written today to solve this problem is (relevant stuff extracted from the project) :
from operator import add, sub, mul, div
import itertools
ops = ['+', '-', '/', '*']
op_map = {'+': add, '-': sub, '/': div, '*': mul}
# iterate over 1 permutation and generates parentheses and operator combinations
def iter_combinations(seq):
if len(seq) == 1:
yield seq[0], str(seq[0])
else:
for i in range(len(seq)):
left, right = seq[:i], seq[i:] # split input list at i`th place
# generate cartesian product
for l, l_str in iter_combinations(left):
for r, r_str in iter_combinations(right):
for op in ops:
if op_map[op] is div and r == 0: # cant divide by zero
continue
else:
yield op_map[op](float(l), r), \
('(' + l_str + op + r_str + ')')
numbers = [4, 8, 6, 2, 15, 50]
target = best_value = 590
best_item = None
for i in range(len(numbers)):
for current in itertools.permutations(numbers, i+1): # generate perms
for value, item in iter_combinations(list(current)):
if value < 0:
continue
if abs(target - value) < best_value:
best_value = abs(target - value)
best_item = item
print best_item
It prints : ((((4*6)+50)*8)-2). Tested it a little with different values and it seems to work correctly. Also I have a function to remove unnecessary parenthesis but it is not relevant to the question so it is not posted.
Problem is that this runs very slowly because of all this permutations, combinations and evaluations. On my mac book air it runs for a few minutes for 1 example. I would like to make it run in a few seconds tops on the same machine, because many quiz game instances will be run at the same time on the server. So the questions are :
Can I speed up current algorithm somehow (by orders of magnitude)?
Am I missing on some other algorithm for this problem which would run much faster?
You can build all the possible expression trees with the given numbers and evalate them. You don't need to keep them all in memory, just print them when the target number is found:
First we need a class to hold the expression. It is better to design it to be immutable, so its value can be precomputed. Something like this:
class Expr:
'''An Expr can be built with two different calls:
-Expr(number) to build a literal expression
-Expr(a, op, b) to build a complex expression.
There a and b will be of type Expr,
and op will be one of ('+','-', '*', '/').
'''
def __init__(self, *args):
if len(args) == 1:
self.left = self.right = self.op = None
self.value = args[0]
else:
self.left = args[0]
self.right = args[2]
self.op = args[1]
if self.op == '+':
self.value = self.left.value + self.right.value
elif self.op == '-':
self.value = self.left.value - self.right.value
elif self.op == '*':
self.value = self.left.value * self.right.value
elif self.op == '/':
self.value = self.left.value // self.right.value
def __str__(self):
'''It can be done smarter not to print redundant parentheses,
but that is out of the scope of this problem.
'''
if self.op:
return "({0}{1}{2})".format(self.left, self.op, self.right)
else:
return "{0}".format(self.value)
Now we can write a recursive function that builds all the possible expression trees with a given set of expressions, and prints the ones that equals our target value. We will use the itertools module, that's always fun.
We can use itertools.combinations() or itertools.permutations(), the difference is in the order. Some of our operations are commutative and some are not, so we can use permutations() and assume we will get many very simmilar solutions. Or we can use combinations() and manually reorder the values when the operation is not commutative.
import itertools
OPS = ('+', '-', '*', '/')
def SearchTrees(current, target):
''' current is the current set of expressions.
target is the target number.
'''
for a,b in itertools.combinations(current, 2):
current.remove(a)
current.remove(b)
for o in OPS:
# This checks whether this operation is commutative
if o == '-' or o == '/':
conmut = ((a,b), (b,a))
else:
conmut = ((a,b),)
for aa, bb in conmut:
# You do not specify what to do with the division.
# I'm assuming that only integer divisions are allowed.
if o == '/' and (bb.value == 0 or aa.value % bb.value != 0):
continue
e = Expr(aa, o, bb)
# If a solution is found, print it
if e.value == target:
print(e.value, '=', e)
current.add(e)
# Recursive call!
SearchTrees(current, target)
# Do not forget to leave the set as it were before
current.remove(e)
# Ditto
current.add(b)
current.add(a)
And then the main call:
NUMBERS = [4, 8, 6, 2, 15, 50]
TARGET = 590
initial = set(map(Expr, NUMBERS))
SearchTrees(initial, TARGET)
And done! With these data I'm getting 719 different solutions in just over 21 seconds! Of course many of them are trivial variations of the same expression.
24 game is 4 numbers to target 24, your game is 6 numbers to target x (0 < x < 1000).
That's much similar.
Here is the quick solution, get all results and print just one in my rMBP in about 1-3s, I think one solution print is ok in this game :), I will explain it later:
def mrange(mask):
#twice faster from Evgeny Kluev
x = 0
while x != mask:
x = (x - mask) & mask
yield x
def f( i ) :
global s
if s[i] :
#get cached group
return s[i]
for x in mrange(i & (i - 1)) :
#when x & i == x
#x is a child group in group i
#i-x is also a child group in group i
fk = fork( f(x), f(i-x) )
s[i] = merge( s[i], fk )
return s[i]
def merge( s1, s2 ) :
if not s1 :
return s2
if not s2 :
return s1
for i in s2 :
#print just one way quickly
s1[i] = s2[i]
#combine all ways, slowly
# if i in s1 :
# s1[i].update(s2[i])
# else :
# s1[i] = s2[i]
return s1
def fork( s1, s2 ) :
d = {}
#fork s1 s2
for i in s1 :
for j in s2 :
if not i + j in d :
d[i + j] = getExp( s1[i], s2[j], "+" )
if not i - j in d :
d[i - j] = getExp( s1[i], s2[j], "-" )
if not j - i in d :
d[j - i] = getExp( s2[j], s1[i], "-" )
if not i * j in d :
d[i * j] = getExp( s1[i], s2[j], "*" )
if j != 0 and not i / j in d :
d[i / j] = getExp( s1[i], s2[j], "/" )
if i != 0 and not j / i in d :
d[j / i] = getExp( s2[j], s1[i], "/" )
return d
def getExp( s1, s2, op ) :
exp = {}
for i in s1 :
for j in s2 :
exp['('+i+op+j+')'] = 1
#just print one way
break
#just print one way
break
return exp
def check( s ) :
num = 0
for i in xrange(target,0,-1):
if i in s :
if i == target :
print numbers, target, "\nFind ", len(s[i]), 'ways'
for exp in s[i]:
print exp, ' = ', i
else :
print numbers, target, "\nFind nearest ", i, 'in', len(s[i]), 'ways'
for exp in s[i]:
print exp, ' = ', i
break
print '\n'
def game( numbers, target ) :
global s
s = [None]*(2**len(numbers))
for i in xrange(0,len(numbers)) :
numbers[i] = float(numbers[i])
n = len(numbers)
for i in xrange(0,n) :
s[2**i] = { numbers[i]: {str(numbers[i]):1} }
for i in xrange(1,2**n) :
#we will get the f(numbers) in s[2**n-1]
s[i] = f(i)
check(s[2**n-1])
numbers = [4, 8, 6, 2, 2, 5]
s = [None]*(2**len(numbers))
target = 590
game( numbers, target )
numbers = [1,2,3,4,5,6]
target = 590
game( numbers, target )
Assume A is your 6 numbers list.
We define f(A) is all result that can calculate by all A numbers, if we search f(A), we will find if target is in it and get answer or the closest answer.
We can split A to two real child groups: A1 and A-A1 (A1 is not empty and not equal A) , which cut the problem from f(A) to f(A1) and f(A-A1). Because we know f(A) = Union( a+b, a-b, b-a, a*b, a/b(b!=0), b/a(a!=0) ), which a in A, b in A-A1.
We use fork f(A) = Union( fork(A1,A-A1) ) stands for such process. We can remove all duplicate value in fork(), so we can cut the range and make program faster.
So, if A = [1,2,3,4,5,6], then f(A) = fork( f([1]),f([2,3,4,5,6]) ) U ... U fork( f([1,2,3]), f([4,5,6]) ) U ... U stands for Union.
We will see f([2,3,4,5,6]) = fork( f([2,3]), f([4,5,6]) ) U ... , f([3,4,5,6]) = fork( f([3]), f([4,5,6]) ) U ..., the f([4,5,6]) used in both.
So if we can cache every f([...]) the program can be faster.
We can get 2^len(A) - 2 (A1,A-A1) in A. We can use binary to stands for that.
For example: A = [1,2,3,4,5,6], A1 = [1,2,3], then binary 000111(7) stands for A1. A2 = [1,3,5], binary 010101(21) stands for A2. A3 = [1], then binary 000001(1) stands for A3...
So we get a way stands for all groups in A, we can cache them and make all process faster!
All combinations for six number, four operations and parenthesis are up to 5 * 9! at least. So I think you should use some AI algorithm. Using genetic programming or optimization seems to be the path to follow.
In the book Programming Collective Intelligence in the chapter 11 Evolving Intelligence you will find exactly what you want and much more. That chapter explains how to find a mathematical function combining operations and numbers (as you want) to match a result. You will be surprised how easy is such task.
PD: The examples are written using Python.
I would try using an AST at least it will
make your expression generation part easier
(no need to mess with brackets).
http://en.wikipedia.org/wiki/Abstract_syntax_tree
1) Generate some tree with N nodes
(N = the count of numbers you have).
I've read before how many of those you
have, their size is serious as N grows.
By serious I mean more than polynomial to say the least.
2) Now just start changing the operations
in the non-leaf nodes and keep evaluating
the result.
But this is again backtracking and too much degree of freedom.
This is a computationally complex task you're posing. I believe if you
ask the question as you did: "let's generate a number K on the output
such that |K-V| is minimal" (here V is the pre-defined desired result,
i.e. 590 in your example) , then I guess this problem is even NP-complete.
Somebody please correct me if my intuition is lying to me.
So I think even the generation of all possible ASTs (assuming only 1 operation
is allowed) is NP complete as their count is not polynomial. Not to talk that more
than 1 operation is allowed here and not to talk of the minimal difference requirement (between result and desired result).
1. Fast entirely online algorithm
The idea is to search not for a single expression for target value,
but for an equation where target value is included in one part of the equation and
both parts have almost equal number of operations (2 and 3).
Since each part of the equation is relatively small, it does not take much time to
generate all possible expressions for given input values.
After both parts of equation are generated it is possible to scan a pair of sorted arrays
containing values of these expressions and find a pair of equal (or at least best matching)
values in them. After two matching values are found we could get corresponding expressions and
join them into a single expression (in other words, solve the equation).
To join two expression trees together we could descend from the root of one tree
to "target" leaf, for each node on this path invert corresponding operation
('*' to '/', '/' to '*' or '/', '+' to '-', '-' to '+' or '-'), and move "inverted"
root node to other tree (also as root node).
This algorithm is faster and easier to implement when all operations are invertible.
So it is best to use with floating point division (as in my implementation) or with
rational division. Truncating integer division is most difficult case because it produces same result for different inputs (42/25=1 and 25/25 is also 1). With zero-remainder integer division this algorithm gives result almost instantly when exact result is available, but needs some modifications to work correctly when approximate result is needed.
See implementation on Ideone.
2. Even faster approach with off-line pre-processing
As noticed by #WolframH, there are not so many possible input number combinations.
Only 3*3*(49+4-1) = 4455 if repetitions are possible.
Or 3*3*(49) = 1134 without duplicates. Which allows us to pre-process
all possible inputs off-line, store results in compact form, and when some particular result
is needed quickly unpack one of pre-processed values.
Pre-processing program should take array of 6 numbers and generate values for all possible
expressions. Then it should drop out-of-range values and find nearest result for all cases
where there is no exact match. All this could be performed by algorithm proposed by #Tim.
His code needs minimal modifications to do it. Also it is the fastest alternative (yet).
Since pre-processing is offline, we could use something better than interpreted Python.
One alternative is PyPy, other one is to use some fast interpreted language. Pre-processing
all possible inputs should not take more than several minutes.
Speaking about memory needed to store all pre-processed values, the only problem are the
resulting expressions. If stored in string form they will take up to 4455*999*30 bytes or 120Mb.
But each expression could be compressed. It may be represented in postfix notation like this:
arg1 arg2 + arg3 arg4 + *. To store this we need 10 bits to store all arguments' permutations,
10 bits to store 5 operations, and 8 bits to specify how arguments and operations are
interleaved (6 arguments + 5 operations - 3 pre-defined positions: first two are always
arguments, last one is always operation). 28 bits per tree or 4 bytes, which means it is only
20Mb for entire data set with duplicates or 5Mb without them.
3. Slow entirely online algorithm
There are some ways to speed up algorithm in OP:
Greatest speed improvement may be achieved if we avoid trying each commutative operation twice and make recursion tree less branchy.
Some optimization is possible by removing all branches where the result of division operation is zero.
Memorization (dynamic programming) cannot give significant speed boost here, still it may be useful.
After enhancing OP's approach with these ideas, approximately 30x speedup is achieved:
from itertools import combinations
numbers = [4, 8, 6, 2, 15, 50]
target = best_value = 590
best_item = None
subsets = {}
def get_best(value, item):
global best_value, target, best_item
if value >= 0 and abs(target - value) < best_value:
best_value = abs(target - value)
best_item = item
return value, item
def compare_one(value, op, left, right):
item = ('(' + left + op + right + ')')
return get_best(value, item)
def apply_one(left, right):
yield compare_one(left[0] + right[0], '+', left[1], right[1])
yield compare_one(left[0] * right[0], '*', left[1], right[1])
yield compare_one(left[0] - right[0], '-', left[1], right[1])
yield compare_one(right[0] - left[0], '-', right[1], left[1])
if right[0] != 0 and left[0] >= right[0]:
yield compare_one(left[0] / right[0], '/', left[1], right[1])
if left[0] != 0 and right[0] >= left[0]:
yield compare_one(right[0] / left[0], '/', right[1], left[1])
def memorize(seq):
fs = frozenset(seq)
if fs in subsets:
for x in subsets[fs].items():
yield x
else:
subsets[fs] = {}
for value, item in try_all(seq):
subsets[fs][value] = item
yield value, item
def apply_all(left, right):
for l in memorize(left):
for r in memorize(right):
for x in apply_one(l, r):
yield x;
def try_all(seq):
if len(seq) == 1:
yield get_best(numbers[seq[0]], str(numbers[seq[0]]))
for length in range(1, len(seq)):
for x in combinations(seq[1:], length):
for value, item in apply_all(list(x), list(set(seq) - set(x))):
yield value, item
for x, y in try_all([0, 1, 2, 3, 4, 5]): pass
print best_item
More speed improvements are possible if you add some constraints to the problem:
If integer division is only possible when the remainder is zero.
If all intermediate results are to be non-negative and/or below 1000.
Well I don't will give up. Following the line of all the answers to your question I come up with another algorithm. This algorithm gives the solution with a time average of 3 milliseconds.
#! -*- coding: utf-8 -*-
import copy
numbers = [4, 8, 6, 2, 15, 50]
target = 590
operations = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: y == 0 and 1e30 or x / y # Handle zero division
}
def chain_op(target, numbers, result=None, expression=""):
if len(numbers) == 0:
return (expression, result)
else:
for choosen_number in numbers:
remaining_numbers = copy.copy(numbers)
remaining_numbers.remove(choosen_number)
if result is None:
return chain_op(target, remaining_numbers, choosen_number, str(choosen_number))
else:
incomming_results = []
for key, op in operations.items():
new_result = op(result, choosen_number)
new_expression = "%s%s%d" % (expression, key, choosen_number)
incomming_results.append(chain_op(target, remaining_numbers, new_result, new_expression))
diff = 1e30
selected = None
for exp_result in incomming_results:
exp, res = exp_result
if abs(res - target) < diff:
diff = abs(res - target)
selected = exp_result
if diff == 0:
break
return selected
if __name__ == '__main__':
print chain_op(target, numbers)
Erratum: This algorithm do not include the solutions containing parenthesis. It always hits the target or the closest result, my bad. Still is pretty fast. It can be adapted to support parenthesis without much work.
Actually there are two things that you can do to speed up the time to milliseconds.
You are trying to find a solution for given quiz, by generating the numbers and the target number. Instead you can generate the solution and just remove the operations. You can build some thing smart that will generate several quizzes and choose the most interesting one, how ever in this case you loose the as close as possible option.
Another way to go, is pre-calculation. Solve 100 quizes, use them as build-in in your application, and generate new one on the fly, try to keep your quiz stack at 100, also try to give the user only the new quizes. I had the same problem in my bible games, and I used this method to speed thing up. Instead of 10 sec for question it takes me milliseconds as I am generating new question in background and always keeping my stack to 100.
What about Dynamic programming, because you need same results to calculate other options?

Infinite loop and recursion in Python

I am working on implementing an iterative deepening depth first search to find solutions for the 8 puzzle problem. I am not interested in finding the actual search paths themselves, but rather just to time how long it takes for the program to run. (I have not yet implemented the timing function).
However, I am having some issues trying to implement the actual search function (scroll down to see). I pasted all the code I have so far, so if you copy and paste this, you can run it as well. That may be the best way to describe the problems I'm having...I'm just not understanding why I'm getting infinite loops during the recursion, e.g. in the test for puzzle 2 (p2), where the first expansion should yield a solution. I thought it may have something to do with not adding a "Return" in front of one of the lines of code (it's commented below). When I add the return, I can pass the test for puzzle 2, but something more complex like puzzle 3 fails, since it appears that the now the code is only expanding the left most branch...
Been at this for hours, and giving up hope. I would really appreciate another set of eyes on this, and if you could point out my error(s). Thank you!
#Classic 8 puzzle game
#Data Structure: [0,1,2,3,4,5,6,7,8], which is the goal state. 0 represents the blank
#We also want to ignore "backward" moves (reversing the previous action)
p1 = [0,1,2,3,4,5,6,7,8]
p2 = [3,1,2,0,4,5,6,7,8]
p3 = [3,1,2,4,5,8,6,0,7]
def z(p): #returns the location of the blank cell, which is represented by 0
return p.index(0)
def left(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc-1]
p[zeroLoc-1] = 0
return p
def up(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc-3]
p[zeroLoc-3] = 0
return p
def right(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc+1]
p[zeroLoc+1] = 0
return p
def down(p):
zeroLoc = z(p)
p[zeroLoc] = p[zeroLoc+3]
p[zeroLoc+3] = 0
return p
def expand1(p): #version 1, which generates all successors at once by copying parent
x = z(p)
#p[:] will make a copy of parent puzzle
s = [] #set s of successors
if x == 0:
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 1:
s.append(left(p[:]))
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 2:
s.append(left(p[:]))
s.append(down(p[:]))
elif x == 3:
s.append(up(p[:]))
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 4:
s.append(left(p[:]))
s.append(up(p[:]))
s.append(right(p[:]))
s.append(down(p[:]))
elif x == 5:
s.append(left(p[:]))
s.append(up(p[:]))
s.append(down(p[:]))
elif x == 6:
s.append(up(p[:]))
s.append(right(p[:]))
elif x == 7:
s.append(left(p[:]))
s.append(up(p[:]))
s.append(right(p[:]))
else: #x == 8
s.append(left(p[:]))
s.append(up(p[:]))
#returns set of all possible successors
return s
goal = [0,1,2,3,4,5,6,7,8]
def DFS(root, goal): #iterative deepening DFS
limit = 0
while True:
result = DLS(root, goal, limit)
if result == goal:
return result
limit = limit + 1
visited = []
def DLS(node, goal, limit): #limited DFS
if limit == 0 and node == goal:
print "hi"
return node
elif limit > 0:
visited.append(node)
children = [x for x in expand1(node) if x not in visited]
print "\n limit =", limit, "---",children #for testing purposes only
for child in children:
DLS(child, goal, limit - 1) #if I add "return" in front of this line, p2 passes the test below, but p3 will fail (only the leftmost branch of the tree is getting expanded...)
else:
return "No Solution"
#Below are tests
print "\ninput: ",p1
print "output: ",DFS(p1, goal)
print "\ninput: ",p2
print "output: ",DLS(p2, goal, 1)
#print "output: ",DFS(p2, goal)
print "\ninput: ",p3
print "output: ",DLS(p3, goal, 2)
#print "output: ",DFS(p2, goal)
The immediate issue you're having with your recursion is that you're not returning anything when you hit your recursive step. However, unconditionally returning the value from the first recursive call won't work either, since the first child isn't guaranteed to be the one that finds the solution. Instead, you need to test to see which (if any) of the recursive searches you're doing on your child states is successful. Here's how I'd change the end of your DLS function:
for child in children:
child_result = DLS(child, goal, limit - 1)
if child_result != "No Solution":
return child_result
# note, "else" removed here, so you can fall through to the return from above
return "No Solution"
A slightly more "pythonic" (and faster) way of doing this would be to use None as the sentinel value rather than the "No Solution" string. Then your test would simply be if child_result: return child_result and you could optionally leave off the return statement for the failed searches (since None is the default return value of a function).
There are some other issues going on with your code that you'll run into once this recursion issue is fixed. For instance, using a global visited variable is problematic, unless you reset it each time you restart another recursive search. But I'll leave those to you!
Use classes for your states! This should make things much easier. To get you started. Don't want to post the whole solution right now, but this makes things much easier.
#example usage
cur = initialPuzzle
for k in range(0,5): # for 5 iterations. this will cycle through, so there is some coding to do
allsucc = cur.succ() # get all successors as puzzle instances
cur = allsucc[0] # expand first
print 'expand ',cur
import copy
class puzzle:
'''
orientation
[0, 1, 2
3, 4, 5
6, 7, 8]
'''
def __init__(self,p):
self.p = p
def z(self):
''' returns the location of the blank cell, which is represented by 0 '''
return self.p.index(0)
def swap(self,a,b):
self.p[a] = self.p[b]
self.p[b] = 0
def left(self):
self.swap(self.z(),self.z()+1) #FIXME: raise exception if not allowed
def up(self):
self.swap(self.z(),self.z()+3)
def right(self):
self.swap(self.z(),self.z()-1)
def down(self):
self.swap(self.z(),self.z()-3)
def __str__(self):
return str(self.p)
def copyApply(self,func):
cpy = self.copy()
func(cpy)
return cpy
def makeCopies(self,s):
''' some bookkeeping '''
flist = list()
if 'U' in s:
flist.append(self.copyApply(puzzle.up))
if 'L' in s:
flist.append(self.copyApply(puzzle.left))
if 'R' in s:
flist.append(self.copyApply(puzzle.right))
if 'D' in s:
flist.append(self.copyApply(puzzle.down))
return flist
def succ(self):
# return all successor states for this puzzle state
# short hand of allowed success states
m = ['UL','ULR','UR','UDR','ULRD','UDL','DL','LRD','DR']
ss= self.makeCopies(m[self.z()]) # map them to copies of puzzles
return ss
def copy(self):
return copy.deepcopy(self)
# some initial state
p1 = [0,1,2,3,4,5,6,7,8]
print '*'*20
pz = puzzle(p1)
print pz
a,b = pz.succ()
print a,b

"Josephus-p‌r‌o‌b‌l‌e‌m" using list in python

I wanted to know if it will be possible to solve the Josepheus problem using list in python.
In simple terms Josephus problem is all about finding a position in a circular arrangement which would be safe if executions were handled out using a skip parameter which is known beforehand.
For eg : given a circular arrangement such as [1,2,3,4,5,6,7] and a skip parameter of 3, the people will be executed in the order as 3,6,2,7,5,1 and position 4 would be the safe.
I have been trying to solve this using list for some time now, but the index positions becomes tricky for me to handle.
a=[x for x in range(1,11)]
skip=2
step=2
while (len(a)!=1):
value=a[step-1]
a.remove(value)
n=len(a)
step=step+skip
large=max(a)
if step>=n:
diff=abs(large-value)
step=diff%skip
print a
Updated the question with code snippet, but i don't think my logic is correct.
Quite simply, you can use list.pop(i) to delete each victim (and get his ID) in a loop. Then, we just have to worry about wrapping the indices, which you can do just by taking the skipped index mod the number of remaining prisoners.
So then, the question solution becomes
def josephus(ls, skip):
skip -= 1 # pop automatically skips the dead guy
idx = skip
while len(ls) > 1:
print(ls.pop(idx)) # kill prisoner at idx
idx = (idx + skip) % len(ls)
print('survivor: ', ls[0])
Test output:
>>> josephus([1,2,3,4,5,6,7], 3)
3
6
2
7
5
1
survivor: 4
In [96]: def josephus(ls, skip):
...: from collections import deque
...: d = deque(ls)
...: while len(d)>1:
...: d.rotate(-skip)
...: print(d.pop())
...: print('survivor:' , d.pop())
...:
In [97]: josephus([1,2,3,4,5,6,7], 3)
3
6
2
7
5
1
survivor: 4
If you do not want to calculate the index, you can use the deque data structure.
My solution uses a math trick I found online here: https://www.youtube.com/watch?v=uCsD3ZGzMgE
It uses the binary way of writing the number of people in the circle and the position where the survivor sits. The result is the same and the code is shorter.
And the code is this:
numar_persoane = int(input("How many people are in the circle?\n")) #here we manually insert the number of people in the circle
x='{0:08b}'.format(int(numar_persoane)) #here we convert to binary
m=list(x) #here we transform it into a list
for i in range(0,len(m)): #here we remove the first '1' and append to the same list
m.remove('1')
m.append('1')
break
w=''.join(m) #here we make it a string again
print("The survivor sits in position",int(w, 2)) #int(w, 2) makes our string a decimal number
if you are looking for the final result only, here is a simple solution.
def JosephusProblem(people):
binary = bin(people) # Converting to binary
winner = binary[3:]+binary[2] # as the output looks like '0b101001'. removing 0b and adding the 1 to the end
print('The winner is',int(winner,2)) #converting the binary back to decimal
If you are looking for the math behind this code, go check out this video:
Josephus Problem(youTube)
it looks worse but easier to understand for beginners
def last(n):
a=[x for x in range(1,n+1)]
man_with_sword = 1
print(a)
while len(a)!=1:
if man_with_sword == a[len(a)-2]: #man_with_sword before last in circle
killed = a[len(a)-1]
a.remove(killed)
man_with_sword=a[0]
elif man_with_sword==a[len(a)-1]: #man_with_sword last in circle
killed = a[0]
a.remove(killed)
man_with_sword=a[0]
else:
i=0
while i < (len(a)//2):
i=a.index(man_with_sword)
killed = a[a.index(man_with_sword)+1]
a.remove(killed)
#pass the sword
man_with_sword=a[i+1] # pass the sword to next ( we killed next)
print (a, man_with_sword) #show who survived and sword owner
i+=1
print (a, man_with_sword,'next circle') #show who survived and sword owner
The total number of persons n and a number k, which indicates that k-1 persons are skipped and a kth person is killed in the circle.
def josephus(n, k):
if n == 1:
return 1
else:
return (josephus(n - 1, k) + k-1) % n + 1
n = 14
k = 2
print("The chosen place is ", josephus(n, k))
This is my solution to your question:
# simple queue implementation<ADT>
class Queue:
def __init__(self):
self.q = []
def enqueue(self,data):
self.q.insert(0,data)
def dequeue(self):
self.q.pop()
def sizeQ(self):
return len(self.q)
def printQ(self):
return self.q
lists = ["Josephus","Mark","Gladiator","Coward"]
to_die = 3
Q = Queue()
# inserting element into Q
for i in lists:
Q.enqueue(i)
# for size > 1
while Q.sizeP() > 1:
for j in range(1,3):
# every third element to be eliminated
Q.enqueue(Q.dequeue())
Q.dequeue()
print(Q.printQ())
def Last_Person(n):
person = [x for x in range(1,n+1)]
x = 0
c = 1
while len(person) > 1:
if x == len(person) - 1:
print("Round ", c, "- Here's who is left: ", person, "Person ", person[x], "killed person", person[0])
person.pop(0)
x = 0
c = c+1
elif x == len(person) - 2:
print("Round ", c, "- Here's who is left: ", person, "Person ", person[x], "killed person", person[x + 1])
person.pop(x+1)
x = 0
c = c + 1
else:
print("Round ", c, "- Here's who is left: ", person, "Person ", person[x], "killed person", person[x + 1])
person.pop(x + 1)
x = x + 1
c = c + 1
print("Person", person[x], "is the winner")
Last_Person(50)

Categories