Numpy:如何模拟格子中的传播

时间:2013-11-22 13:32:27

标签: python numpy

这是我的低效Python代码:

import numpy as np 
import random  

matrix = np.empty( (100,100), dtype=bool )

matrix[:,:] = False
matrix[50,50] = True

def propagate(matrix, i, j):
    for (di,dj) in [ (1,0), (0,1), (-1,0), (0,-1) ]:
        (ni,nj) = (i+di, j+dj)
        if matrix[ni,nj] and flip_coin_is_face():
              matrix[i,j] = True 

def flip_coin_is_face():
    return random.uniform(0,1) < 0.5

for k in xrange(1000):
   for i in xrange(1,99):
      for j in xrange(1,99):
          propagate(matrix, i, j)

基本上从矩阵的中心传播True状态。由于我在Python中编写循环和传播规则,因此这当然非常慢。

我的问题是,如何使用Numpy索引尽可能快地进行此操作?

2 个答案:

答案 0 :(得分:1)

我对numpy不太好,但要通过矩阵“传播”,你可以使用像广度优先搜索这样的东西。如果您之前没有使用它,它看起来像这样:

import Queue

def neighbors(i, j, mat_shape):
    rows = mat_shape[0]
    cols = mat_shape[1]
    offsets = [(-1, 0), (1, 0), (0, 1), (0, -1)]
    neighbors = []
    for off in offsets:
        r = off[0]+i
        c = off[1]+j
        if 0 <= r and r <= rows and 0 <= c and c <= cols:
            neighbors.append((r,c))
    return neighbors

def propagate(matrix, i, j):
    # 'parents' is used in two ways. first, it tells us where we've already been
    #  second, it tells us w
    parents = np.empty(matrix.shape)
    parents[:,:] = None
    # first-in-first-out queue. initially it just has the start point
    Q = Queue.Queue()
    # do the first step manually; start propagation with neighbors
    matrix[i,j] = True
    for n in neighbors(i,j,matrix.shape):
        Q.put(n)
        parents[n[0],n[1]] = (i,j)
    # initialization done. on to the propagation
    while not Q.empty():
        current = Q.get() # get's front element and removes it
        parent = parents[current[0], current[1]]
        matrix[current[0], current[1]] = matrix[parent[0], parent[1]] and flip_coin_is_face()
        # propagate to neighbors, in order
        for next in neighbors(current[0], current[1], matrix.shape):
            # only propagate there if we haven't already
            if parents[next[0], next[1]] is None:
                parents[next[0], next[1]] = current
                Q.put(next)
    return matrix

你可能会更聪明并且提前切断传播(因为一旦它到达False,它将永远不会再次获得True。但对于100x100,这应该足够快。

答案 1 :(得分:1)

我可以想到一种方法,但它与原始代码不同。也就是说,您可以在每个步骤数组中过滤掉一个(k循环),将每个值传播到它的neiboughours,即滚动骰子4次,然后评估下一步数组。每个操作都可以使用numpy one liner(使用wherereshape+*作为矩阵),因此不会有内部循环。

实际上,差异在于我们没有考虑在一个步骤中传播的值,一次评估所有更改。事实上,它将减慢,并且我认为,根据完成所有矩阵所需的步骤,传播速度会明显减慢。

如果这种方法没问题,我可以提出一些代码。