this is famous path counting problem , i am trying to solve it using memoization.
Enlighten me!
def pathCounter(a,b):
matrix = [[0 for i in xrange(a)] for i in xrange(b)]
if a==0 or b==0:
return 1
if matrix[a][b]:
return matrix[a][b]
print matrix[a][b]
matrix[a][b]=pathCounter(a,b-1)+pathCounter(a-1,b)
return matrix[2][2]
if __name__=='__main__':
k=pathCounter(2,2)
print k
I believe your trying to solve this problem.
If that is the case, then you are correct that it would be sensible to solve with recursion.
If you imagine each corner of the grid as a node, then you want to a recursive function that simply takes a parameter of the node it is at (x, y). In the function, it first needs to check if the position that it was called at is the bottom right vertex of the grid. If it is, the function adds one to the path count (as a path is finished when it reaches this corner) and then returns. Otherwise, this function just calls two more of itself (this is the recursion), one to its right (so y+1) and one to its left (x+1). An added step is to check that the coordinates are in the grid before calling them as a node in the middle of the bottom row for instance shouldn't call a node below it as that would be off the grid.
Now you have the recursive function defined, all you need to do now is declare a variable to store the path count. And call the recursive function from the coordinate (0,0).
However, as I am sure you have seen, this solution does not complete in reasonable time so it is necessary that you use memoization - speeding it up by caching the nodes so that the same sections of paths aren't calculated twice.
It also makes coding it more simple if as you have done, we work from the bottom right corner up to the top left corner. One last thing is that if you use a dictionary then the code becomes clearer.
The final code should look something like:
cache = {}
def pathCounter(x, y):
if x == 0 or y == 0:
return 1
if (x,y) in cache:
return cache[(x,y)]
cache[(x,y)] = pathCounter(x, y-1) + pathCounter(x-1, y)
return cache[(x,y)]
print(pathCounter(2,2))
this gives the expected result of 6.
I'll leave you to do the 20x20 grid. Hope this helps!
You made a few errors in your implementation of the algorithm. If your using a recursive approach you do not have to use the grid because you want require any of the stored data, actually. You only need to return the two possible sub-paths from your current position - that's it! Therefore, you need to make some changes in the main idea of your code.
I tried to keep as much of your original code as possible, but still make it working:
def pathCounterNaive(width, height, startX = 0, startY = 0):
if startX >= width or startY >= height:
return 0
if startX == width-1 and startY == height-1:
return 1
return pathCounter(width,height, startX+1, startY) + pathCounter(width,height, startX, startY+1)
slowK=pathCounterNaive(3,3)
print(slowK)
Please keep in mind, that the parameters width and height represent the number of vertices, and are therefore not 2 but 3 for a 2x2 grid. As this code is using pure recursion it is very slow. If you want to use your memorization approach, you have to modify your code like this:
import numpy as np
def pathCounter(width, height):
grid = np.zeros((height+1, width+1))
def pathCounterInternal(x, y):
if x==0 or y==0:
return 1
grid[x, y] = pathCounterInternal(x,y-1)+pathCounterInternal(x-1,y)
return grid[x, y]
grid[width, height] = pathCounterInternal(width, height)
return grid[width, height]
k=pathCounter(2,2)
print(k)
Here you have to call it with 2 as the parameter for a 2x2 grid. This code is much faster due to the caching of already calculated paths.
Related
Problem
I recently found a need to determine if my points are inside of a polygon. So I learned about this approach in C++ and adapted it to python. However, the C++ code I was studying isn't quite right I think? I believe I have fixed it, but I am not quite sure so I was hoping folks brighter than me might help me caste some light on this?
The theorem is super simple and the idea is like this, given an nth closed polygon you draw an arbitrary line, if your point is inside, you line will intersect with the edges an odd number of times. Otherwise, you will be even and it is outside the polygon. Pretty freaking cool.
I had the following test cases:
polygon_x = [5, 5, 11, 10]
polygon_y = [5, 10, 5, 10]
test1_x = 6
test1_y = 6
result1 = point_in_polygon(test1_x, test1_y, polygon_x, polygon_y)
print(result1)
test2_x = 13
test2_y = 5
result2 = point_in_polygon(test2_x, test2_y, polygon_x, polygon_y)
print(result2)
The above would give me both false if I defined it as follows:
if polygon_x[i] < polygon_x[(i+1) % length]:
temp_x = polygon_x[i]
temp_y = polygon_x[(i+1) % length]
else:
temp_x = polygon_x[(i+1) % length]
temp_y = polygon_x[i]
This is wrong! I should be getting true for result1 and then false for result2. So clearly, something is funky.
The code I was reading in C++ makes sense except for the above. In addition, it failed my test case which made me think that temp_y should be defined with polygon_y and not polygon_x. Sure enough, when I did this, my test case for (6,6) passes. It still fails when my points are on the line, but as long as I am inside the polygon, it will pass. Expected behavior.
Polygon code adopted to python
def point_in_polygon(self, target_x, target_y, polygon_x, polygon_y):
print(polygon_x)
print(polygon_y)
#Variable to track how many times ray crosses a line segment
crossings = 0
temp_x = 0
temp_y = 0
length = len(polygon_x)
for i in range(0,length):
if polygon_x[i] < polygon_x[(i+1) % length]:
temp_x = polygon_x[i]
temp_y = polygon_y[(i+1) % length]
else:
temp_x = polygon_x[(i+1) % length]
temp_y = polygon_y[i]
print(str(temp_x) + ", " + str(temp_y))
#check
if target_x > temp_x and target_x <= temp_y and (target_y < polygon_y[i] or target_y <= polygon_y[(i+1)%length]):
eps = 0.000001
dx = polygon_x[(i+1) % length] - polygon_x[i]
dy = polygon_y[(i+1) % length] - polygon_y[i]
k = 0
if abs(dx) < eps:
k = 999999999999999999999999999
else:
k = dy/dx
m = polygon_y[i] - k * polygon_x[i]
y2 = k*target_x + m
if target_y <= y2:
crossings += 1
print(crossings)
if crossings % 2 == 1:
return True
else:
return False
Summary
Can someone please explain to me what the temp_x and temp_y approaches are doing? Also, if my fix for redefining the temp_x for polygon_x and temp_y for polygon_y is the correct approach? I doubt it. Here is why.
What is going on for temp_x and temp_y doesn't quite make sense to me. For i = 0, clearly polygon_x[0] < polygon_x[1] is false, so we get temp_x[1] = 5 and temp_y[0] = 5. That is (5,5). This just happens to be one of my pairs. However, suppose I feed the algorithm my points out of order (by axis, pairwise integrity is always a must), something like:
x = [5, 10, 10, 5]
y = [10,10, 5, 5]
In this case, when i = 0, we get temp_x[1] = 10 and temp_y[0] = 10. Okay, by coincidence (10,10). I also tested points against the "corrected" algorithm (9,9) and it is still inside. In short, I am trying to find a counterexample, for why my fix won't work, but I can't. If this is working, I need to understand what the method is doing and hope someone could help explain it to me?
Regardless, if I am right or wrong, I would appreciate it if someone could help shed some better light on this problem. I'm even open to solving the problem in a more efficient way for n-polygons, but I want to make sure I am understanding code correctly. As a coder, I am uncomfortable with a method that doesn't quite make sense.
Thank you so much for listening to my thoughts above. Any suggestions greatly welcomed.
You've misunderstood what the x1 and x2 values in the linked C++ code are for, and that misunderstanding has caused you to pick inappropriate variable names in Python. Both of the variables contain x values, so temp_y is a very misleading name. Better names might be min_x and max_x, since they are the minimum and maximum of the x values of the vertices that make up the polygon edge. A clearer version of the code might be written as:
for i in range(length):
min_x = min(polygon_x[i], polygon_x[(i+1)%length])
max_x = max(polygon_x[i], polygon_x[(i+1)%length])
if x_min < target_x <= x_max:
# ...
This is perhaps a little less efficient than the C++ style of code, since calling both min and max will compare the values twice.
Your comment about the order of the points suggests that there's a further misunderstanding going on, which might explain the unexpected results you were seeing when setting temp_y to a value from polygon_x. The order of the coordinates in the polygon lists is important, as the edges go from one coordinate pair to the next around the list (with the last pair of coordinates connecting to the first pair to close the polygon). If you reorder them, the edges of the polygon will get switched around.
The example coordinates you give in your code (polygon_x = [5, 5, 11, 10] and polygon_y = [5, 10, 5, 10]) don't describe a normal kind of polygon. Rather, you get a (slightly lopsided) bow-tie shape, with two diagonal edges crossing each other like an X in the middle. That's not actually a problem for this algorithm though.
However, the first point you're testing lies exactly on one of those diagonal edges (the one that wraps around the list, from the last vertex, (10, 10) to the first, (5, 5)). Whether the code will decide it's inside or outside of the polygon likely comes down to floating point rounding and the choice of operator between < or <=. Either answer could be considered "correct" in this situation.
When you reordered the coordinates later in the question (and incidentally change an 11 to a 10), you turned the bow-tie into a square. Now the (6, 6) test is fully inside the shape, and so the code will work if you don't assign a y coordinate to the second temp variable.
I'm writing a function to count the possible paths of length M in an N-dimensions grid starting from points specified in list X_n where the dimensions of the grid are given in list D_n.
I am passing the current coordinates and dimensions of the grid to the Solve function with lists. However, this means I am making many list copies, as can be seen below.
def Solve(X_n, D_n, M):
"""Find number of paths of length M in grid of dimensions D_n we can get starting at X_n"""
#using dynamic methods to avoid unnecessary calculations by storing number of paths
# from a given grid member that are available. This will be 2^N except for edge cases
if M == 1:
return solve_grid[tuple(X_n)] if solve_grid[tuple(X_n)] else count_em(X_n, D_n)
#identify which current coordinates are at an edge and don't modify these in wrong direction
diff = np.subtract(D_n, X_n)
good_add = [i for i, d in enumerate(diff) if d!= 0]
good_subtract = [i for i, x in enumerate(X_n) if x != 0]
return_val = 0
#here's my concern: what's going to happen with all these lists?
#is there a better way to handle this?
for idx in good_add:
new_x = list(X_n)
new_x[idx] += 1
return_val += Solve(new_x, D_n, M-1)
for idx in good_subtract:
new_x = list(X_n)
new_x[idx] -= 1
return_val += Solve(new_x, D_n, M-1)
return return_val
My understanding is that Python has a write-only type memory management system, so when I am creating many duplicate lists (as this function certainly will), these duplicate objects will all point to the same item so long as they are not modified. This seems like the above should be not so bad...
Is this ok memory-wise or will it blow up?
If it will blow up, what's a smart way to do this with lists (they're so convenient)?
If not, is using an f(*args) style function the best way to recursively pass coordinates and dimensions?
I was wondering how the flow of this recursive algorithm works: an inversion counter based on merge-sort. When I looked at the diagrams of the merge-sort recursion tree, it seemed fairly lucid; I thought that the leaves would keep splitting until each leaf was a single unit, then merge() would start combining them; and therefore, start 'moving back up' the tree -- so to speak.
But in the code below, if we print out this function with a given array print(sortAndCount(test_case)) then we're actually getting our 'final' output from the merge() function, not the return statement in sortAndCount()? So in the code below, I thought that the sortAndCount() method would call itself over and over in (invCountA, A) = sortAndCount(anArray[:halfN]) until reaching the base case and then moving on to processing the next half of the array -- but now that seems incorrect. Can someone correct my understanding of this recursive flow? (N.b. I truncated some of the code for the merge() method since I'm only interested the recursive process.)
def sortAndCount(anArray):
N = len(anArray)
halfN = N // 2
#base case:
if N == 1: return (0, anArray)
(invCountA, A) = sortAndCount(anArray[:halfN])
(invCountB, B) = sortAndCount(anArray[halfN:])
(invCountCross, anArray) = merge(A, B)
return (invCountA + invCountB + invCountCross, anArray)
def merge(listA, listB):
counter = 0
i, j = 0, 0
#some additional code...
#...
#...
#If all items in one array have been selected,
#we just return remaining values from other array:
if (i == Asize):
return (counter, output_array + listB[j:])
else:
return (counter, output_array + listA[i:])
The following image created using rcviz shows the order of recursive call, as explained in the documentation the edges are numbered by the order in which they were traversed by the execution.The edges are colored from black to grey to indicate order of traversal : black edges first, grey edges last.:
So if we follow the steps closely we see that first we traverse the left half of the original array completely then the right.
Is there any function in PyQt4 to help me decide if a point is on the perimeter of a QPolygon? For example:
from PyQt4 import QtGui
from PyQt4.QtCore import Qt, QPoint as QP
polygon = QtGui.QPolygon([QP(0, 1), QP(3,7), QP(4, 6), QP(4,3), QP(2,1), QP(0,1])
The function should return true if I pass QP(1,3), QP(4,5), QP(3,2) or QP(1,1) to it.
This is a tough one indeed. I played around a lot with several methods of QPolygon like intersected, united, subtracted but none brought any success.
For example I thought this might work: Copy the polygon, add the point to the copy and then check if the result is empty. If the point lies on the perimeter of the polygon both the original and the copy should have the same shape and therefore the result should be empty.
def on_perimeter(poly, point):
poly2 = poly + QtGui.QPolygon() # copy the polygon
poly2.add(point)
return poly.subtracted(poly2).isEmpty()
However a polygon seems to be 'drawn' in the order the points are given thus if you just add the point this leads to some other shape. For example consider the points (0,0) (0,2) (2.2) (2,0) which form a square and you want to check (0,1). Then if you just add the point at the end this will 'connect" (2,0) with (0,1) and (0,1) with (0,0) since a polygon has to be a closed form. This gives some other shape. Thus you would have to insert the point at the right position to get the same shape. For this example it would be right after (0,0). So I thought, ok, lets try the above with all possible permutations and there will be only one configuration (and its transformations resulting from rotation and inversion) such that the result of the subtraction is empty.
import itertools
def on_perimeter(poly, point):
points = [point] # the points of the new polygon
for ii in range(0, poly.size()):
points += [poly.point(ii)]
permuts = list(itertools.permutations(points)) # all possible permutations
checks = 0
for permut in permuts:
checks += int(poly.subtracted(QtGui.QPolygon(list(permut))).isEmpty())
return checks
But somehow this doesn't work either. Trying out your example I get for QP(4,5) and QP(3,2) a value of checks = 10 for QP(1,1) checks = 20 and for QP(1,3) checks = 0. What I would have expected is to get checks = 12 for all of the points (since they all lie on the perimeter). 12 because poly2 is made of 6 points so you can rotate the points 6 times and do the same after you inverted the order so have 12 different configurations contained in permuts leading to the same shape. Furthermore if the subtraction is performed the other way round (i.e. QtGui.QPolygon(list(permut)).subtracted(poly).isEmpty()) I get True for every point also for points not even lying within the polygon but outside.
I tried similar things using united and intersected instead of isEmpty in the above function:
tmp = QtGui.QPolygon(list(permut))
checks += int(poly.intersected(tmp) == poly.united(tmp))
Same here, it should only evaluate as True if the point is actually lying on the perimeter. But this gives back False for almost every point I checked of your above example.
I didn't take a look at the source code of the methods of QPolygon (if any available) but it appears that there is some weird stuff happening.
So I would suggest you to write an own method which evaluates for all lines in the polygon if the point lies on one of it.
def on_perimeter(poly, point):
lines = []
for ii in range(1, poly.size()):
p1 = poly.point(ii-1)
p2 = poly.point(ii)
lines += [ ( (p1.x(), p1.y()), (p2.x(), p2.y()) ) ]
lines += [ ( (poly.last.x(), poly.last.y()), (poly.first.x(), poly.first.y()) ) ]
for line in lines:
dx = line[1][0] - line[0][0]
dy = line[1][1] - line[0][1]
if abs(dx) > abs(dy) and dx*dy != 0 or dx == 0 and dy == 0: # abs(slope) < 1 and != 0 thus no point with integer coordinates can lie on this line
continue
if dx == 0:
if point.x() == line[0][0] and (point.y()-line[[0][1])*abs(dy)/dy > 0 and (line[1][1]-point.y())*abs(dy)/dy > 0:
return True
if dy == 0:
if point.y() == line[0][1] and (point.x()-line[[0][0])*abs(dx)/dx > 0 and (line[1][0]-point.x())*abs(dx)/dx > 0:
return True
dx2 = point.x() - line[0][0]
dy2 = point.y() - line[0][1]
if dx*dx2 < 0 or dy*dy2 < 0:
continue
if abs(dx) % abs(dx2) == 0 and abs(dy) % abs(dy2) == 0:
return True
return False
This appears to be a bit heavy but it is important to perform all calculations with integers only since you could get wrong results due to floating point precision (QPolygon takes integer points only anyway). Although not tested yet it should work.
Okay, so I've got a piece of Python code which really needs optimizing.
It's a Game-of-Life iteration over a small (80x60-pixel) image and extracts the RGB values from it.
currently using nested for-loops; I'd rather swap out those for loops for the faster map() c function, but if I do that I can't figure out how I can get the x,y values, nor the local values defined out of the scope of the functions I'd need to define.
would using map() be any faster than this current set of for loops? How could I use it and still get x,y?
I currently use pygame Surfaces, and I've tried the surfarray/pixelarray modules, but since I'm changing/getting every pixel, it's a lot slower than Surface.get_at()/set_at().
Also, slightly irrelevant... do you think this could be made quicker if Python wasn't traversing a list of numbers but just incrementing a number, like in other languages? Why doesn't python include a normal for() as well as their foreach()?
The amount of conditionals there probably makes things slower too, right? The slowest part is checking for neighbours (where it builds the list n)... I replaced that whole bit with slice access on a 2D array but it doesn't work properly.
Redacted version of code:
xr = xrange(80)
yr = xrange(60)
# surface is an instance of pygame.Surface
get_at = surface.get_at()
set_at = surface.set_at()
for x in xr:
# ....
for y in yr:
# ...
pixelR = get_at((x,y))[0]
pixelG = get_at((x,y))[1]
pixelB = get_at((x,y))[2]
# ... more complex stuff here which changes R,G,B values independently of each other
set_at((x,y),(pixelR,pixelG,pixelB))
Full version of the function:
# xr, yr = xrange(80), xrange(60)
def live(surface,xr,yr):
randint = random.randint
set_at = surface.set_at
get_at = surface.get_at
perfect = perfectNeighbours #
minN = minNeighbours # All global variables that're defined in a config file.
maxN = maxNeighbours #
pos = actual # actual = (80,60)
n = []
append = n.append
NEIGHBOURS = 0
for y in yr: # going height-first for aesthetic reasons.
decay = randint(1,maxDecay)
growth = randint(1,maxGrowth)
for x in xr:
r, g, b, a = get_at((x,y))
del n[:]
NEIGHBOURS = 0
if x>0 and y>0 and x<pos[0]-1 and y<pos[1]-1:
append(get_at((x-1,y-1))[1])
append(get_at((x+1,y-1))[1])
append(get_at((x,y-1))[1])
append(get_at((x-1,y))[1])
append(get_at((x+1,y))[1])
append(get_at((x-1,y+1))[1])
append(get_at((x+1,y+1))[1])
append(get_at((x,y+1))[1])
for a in n:
if a > 63:
NEIGHBOURS += 1
if NEIGHBOURS == 0 and (r,g,b) == (0,0,0): pass
else:
if NEIGHBOURS < minN or NEIGHBOURS > maxN:
g = 0
b = 0
elif NEIGHBOURS==perfect:
g += growth
if g > 255:
g = 255
b += growth
if b > growth: b = growth
else:
if g > 10: r = g-10
if g > 200: b = g-100
if r > growth: g = r
g -= decay
if g < 0:
g = 0
b = 0
r -= 1
if r < 0:
r = 0
set_at((x,y),(r,g,b))
What's making your code slow is probably not the loops, they are incredibly fast.
What slows done your code are the number of function calls. For example
pixelR = get_at((x,y))[0]
pixelG = get_at((x,y))[1]
pixelB = get_at((x,y))[2]
is a lot slower than (about 3 times I guess)
r, g, b, a = get_at((x,y))
Every get_at, set_at call locks the surface, therefore it's faster to directly access the pixels using the available methods. The one that seems most reasonable is Surface.get_buffer.
Using map doesn't work in your example, because you need the indexes. With as few as 80 and 60 numbers it might even be faster to use range() instead of xrange().
map(do_stuff, ((x, y) for x in xrange(80) for y in xrange(60)))
where do_stuff would presumably be defined like so:
def do_stuff(coords):
r, g, b, a = get_at(coords)
# ... whatever you need to do with those ...
set_at(coords, (r, g, b))
You could alternatively use a list comprehension instead of a generator expression as the second argument to map (replace ((x, y) ...) with [(x, y) ...]) and use range instead of xrange. I'd say that it's not very likely to have a significant effect on performance, though.
Edit: Note that gs is certainly right about the for loops not being the main thing in need of optimisation in your code... Cutting down on superfluous calls to get_at is more important. In fact, I'm not sure if replacing the loops with map will actually improve performance here at all... Having said that, I find the map version more readable (perhaps because of my FP background...), so here you go anyway. ;-)
Since you are reading and rewriting every pixel, I think you can get the best speed improvement by not using a Surface.
I suggest first taking your 80x60 image and converting it to a plain bitmap file with 32-bit pixels. Then read the pixel data into a python array object. Now you can walk over the array object, reading values, calculating new values, and poking the new values into place with maximum speed. When done, save your new bitmap image, and then convert it to a Surface.
You could also use 24-bit pixels, but that should be slower. 32-bit pixels means one pixel is one 32-bit integer value, which makes the array of pixels much easier to index. 24-bit packed pixels means each pixel is 3 bytes, which is much more annoying to index into.
I believe you will gain much more speed out of this approach than by trying to avoid the use of for. If you try this, please post something here to let us know how well it worked or didn't. Good luck.
EDIT: I thought that an array has only a single index. I'm not sure how you managed to get two indexes to work. I was expecting you to do something like this:
def __i(x, y):
assert(0 <= x < 80)
assert(0 <= y < 60)
i = (y*80 + x) * 4
return i
def red(x, y):
return __a[__i(x, y)]
def green(x, y):
return __a[__i(x, y) + 1]
def blue(x, y):
return __a[__i(x, y) + 2]
def rgb(x, y):
i = __i(x, y)
return __a[i], __a[i + 1], __a[i + 2]
def set_rgb(x, y, r, g, b):
i = __i(x, y)
_a[i] = r
_a[i + 1] = g
_a[i + 2] = b
# example:
r, g, b = rgb(23, 33)
Since a Python array can only hold a single type, you will want to set the type to "unsigned byte" and then index like I showed.
Where of course __a is the actual array variable.
If none of this is helpful, try converting your bitmap into a list, or perhaps three lists. You can use nested lists to get 2D addressing.
I hope this helps. If it is not helpful, then I am not understanding what you are doing; if you explain more I'll try to improve the answer.