N-Queen Problem: Python 2.6.5 vs PyPy 1.5.0
aminsblog.wordpress.com
aminsblog.wordpress.com
If you are optimizing in LOC, it can come down to basically a single expression; of course that's not a reason to write it as a one-liner:
def n_queen(n):
return (p for p in itertools.permutations(xrange(n))
if all(j-i != abs(p[i] - p[j])
for i in xrange(n - 1)
for j in xrange(i + 1, n)))from http://nsl.com/papers/qn.htm , the code that computes the solution is
qn:{[n],/{:[n=#*x;,*x;,/_f'f x,\:/:(!n)_dvl,/x]}'(f:0 -1 1+/:)@!n}
And it uses backtracking, which makes it infinitely faster.But armin isn't optimizing LOC.
It's also fast enough for low n (up to 8). Why write more code when you can get your result with less? Maybe the time he's saved with this approach can now be used writing a deduplicator (to cull out mirrored and rotated solutions).
Maybe the point of the article was not only to show how fast PyPy is, but how convenient itertools.permutation() is. You can't show the convenience of itertools by not using it.
However... You know what? When I was asked to write a n-queens solver recently, I also wrote a backtracker. It just doesn't mean I did it better than this guy.
Yes, it's twice as long and harder to read. Improvements, anyone?
def hit_last(p):
x = p[-1]
i = len(p)-1
for j in range(i):
y = p[j]
if x == y or i - j == abs(x - y):
return True
return False
def n_queen(n):
p = [0]
while True: # Begin iter w/ board good, except maybe last Q
full = len(p) == n
hit = hit_last(p)
if full or hit: # Will we backtrack?
if not hit: # Found solution?
yield p
while len(p) > 0 and p[-1] == n-1:
p.pop()
if len(p) == 0:
return
p[-1] += 1
else:
p.append(0) alex@alex-gaynor-laptop:/tmp$ time python queens.py
real 0m16.837s
user 0m16.820s
sys 0m0.000s
alex@alex-gaynor-laptop:/tmp$ time pypy queens.py
real 0m2.548s
user 0m2.530s
sys 0m0.010sThis was ~5 years ago, and I don't remember the exact magnitude of the speedup on Java vs. C. I do remember it being rather less than I was expecting.
==== solution 1 =====
(0, 2, 5, 7, 9, 4, 8, 1, 3, 6)
terminate called after throwing an instance of '__shedskin__::TypeError*'
Aborted