Iterar sobre matriz 2D em uma espiral circular em expansão

Given ann porn matrixM, na linhai e colunaj, Gostaria de percorrer todos os valores vizinhos em uma espiral circula

O objetivo de fazer isso é testar alguma função,f, que depende de M, para encontrar o raio longe de(i, j) no qualf retornaTrue. Então,f se parece com isso

def f(x, y):
    """do stuff with x and y, and return a bool"""

e seria chamado assim:

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

Ondecircle_around é a função que retorna (um iterador para) os índices em uma espiral circular. Então, para cada ponto emM, esse código calcularia e armazenaria o raio a partir daquele ponto em quef retornaTrue.

Se houver uma maneira mais eficiente de calcularR, Eu também estaria aberto a iss

Atualizar

Obrigado a todos que enviaram respostas. Eu escrevi uma função curta para plotar a saída do seucircle_around iteradores, para mostrar o que eles fazem. Se você atualizar sua resposta ou postar uma nova, poderá usar este código para validar sua solução.

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")

Aqui estão os resultados:plot(circle_around(0, 0), "F.J"):

plot(circle_around(0, 0, 10), "WolframH"):

Eu codifiquei a sugestão de magnésio da seguinte forma:

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"):

Como você pode ver, nenhum dos resultados que satisfazem a interface que eu estou procurando produziu uma espiral circular que cobre todos os índices em torno de 0, 0. O FJ é o mais próximo, embora o WolframH atinja os pontos certos, apenas não em ordem espiral.

questionAnswers(14)

yourAnswerToTheQuestion