Given an n
by n
matrix M
, at row i
and column j
, I'd like to iterate over all the neighboring values in a circular spiral.
The point of doing this is to test some function, f
, which depends on M, to find the radius away from (i, j)
in which f
returns True
. So, f
looks like this:
def f(x, y):
"""do stuff with x and y, and return a bool"""
and would be called like this:
R = numpy.zeros(M.shape, dtype=numpy.int)
# for (i, j) in M
for (radius, (cx, cy)) in circle_around(i, j):
if not f(M[i][j], M[cx][cy]):
R[cx][cy] = radius - 1
break
Where circle_around
is the function that returns (an iterator to) indices in a circular spiral. So for every point in M
, this code would compute and store the radius from that point in which f
returns True
.
If there's a more efficient way of computing R
, I'd be open to that, too.
Update:
Thanks to everyone who submitted answers. I've written a short function to plot the output from your circle_around
iterators, to show what they do. If you update your answer or post a new one, you can use this code to validate your solution.
from matplotlib import pyplot as plt
def plot(g, name):
plt.axis([-10, 10, -10, 10])
ax = plt.gca()
ax.yaxis.grid(color='gray')
ax.xaxis.grid(color='gray')
X, Y = [], []
for i in xrange(100):
(r, (x, y)) = g.next()
X.append(x)
Y.append(y)
print "%d: radius %d" % (i, r)
plt.plot(X, Y, 'r-', linewidth=2.0)
plt.title(name)
plt.savefig(name + ".png")
Here are the results:
plot(circle_around(0, 0), "F.J")
:
plot(circle_around(0, 0, 10), "WolframH")
:
I've coded up Magnesium's suggestion as follows:
def circle_around_magnesium(x, y):
import math
theta = 0
dtheta = math.pi / 32.0
a, b = (0, 1) # are there better params to use here?
spiral = lambda theta : a + b*theta
lastX, lastY = (x, y)
while True:
r = spiral(theta)
X = r * math.cos(theta)
Y = r * math.sin(theta)
if round(X) != lastX or round(Y) != lastY:
lastX, lastY = round(X), round(Y)
yield (r, (lastX, lastY))
theta += dtheta
plot(circle_around(0, 0, 10), "magnesium")
:
As you can see, none of the results that satisfy the interface I'm looking for have produced a circular spiral that covers all of the indices around 0, 0. F.J's is the closest, although WolframH's hits the right points, just not in spiral order.
Here is a loop based implementation for
circle_around()
: