gpt4 book ai didi

python - 一条一条运行时效果不错,循环使用时出错

转载 作者:太空宇宙 更新时间:2023-11-03 11:55:46 28 4
gpt4 key购买 nike

我有一个由 1 和 0 组成的二维网格。集群被定义为相邻的非对角线集。例如,如果我们看一个网格:

[[0 0 0 0 0]
[1 1 1 1 1]
[1 0 0 0 1]
[0 1 0 0 1]
[1 1 1 1 0]]

一个集群将是一组坐标(实际上我为此使用列表,但这并不重要):

c1=[[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [2, 1], [2, 4], [3, 4]]

此网格中的另一个集群由下式给出:

c2=[[3,1], [4, 0], [4, 1], [4, 2], [4, 3]]

现在,我创建了一个方法,对于给定的起始坐标(如果它的值为 1),返回该点所属的簇(例如,如果我选择 [1,1] 坐标,它将返回 c1 ).
为了进行测试,我将选择一个点 (1, 1) 和一个小网格。这是结果好的时候的输出:

Number of recursions: 10
Length of cluster: 10
[[1 1 1 0 1]
[1 1 0 1 1]
[0 1 0 0 1]
[1 1 1 0 0]
[0 1 0 1 1]]

[[1 1 1 0 0]
[1 1 0 0 0]
[0 1 0 0 0]
[1 1 1 0 0]
[0 1 0 0 0]]

我试图了解当簇大小变大时我的算法有多快。如果我运行该程序然后重新运行它,并多次这样做,它总是会给出好的结果。如果我使用循环,它就会开始给出错误的结果。这是一种可能的输出测试场景:

Number of recursions: 10
Length of cluster: 10
[[1 1 1 0 1]
[1 1 0 1 1]
[0 1 0 0 1]
[1 1 1 0 0]
[0 1 0 1 1]]

[[1 1 1 0 0]
[1 1 0 0 0]
[0 1 0 0 0]
[1 1 1 0 0]
[0 1 0 0 0]]
Number of recursions: 8
Length of cluster: 8
[[0 1 1 1 0]
[1 1 1 0 0]
[1 0 0 0 0]
[1 1 1 0 1]
[1 1 0 0 0]]

[[0 0 0 0 0] - the first one is always good, this one already has an error
[1 1 0 0 0]
[1 0 0 0 0]
[1 1 1 0 0]
[1 1 0 0 0]]
Number of recursions: 1
Length of cluster: 1
[[1 1 1 1 1]
[0 1 0 1 0]
[0 1 0 0 0]
[0 1 0 0 0]
[0 1 1 0 1]]

[[0 0 0 0 0] - till end
[0 1 0 0 0]
[0 0 0 0 0]
[0 0 0 0 0]
[0 0 0 0 0]]
Number of recursions: 1
Length of cluster: 1
[[1 1 1 1 1]
[0 1 1 0 0]
[1 0 1 1 1]
[1 1 0 1 0]
[0 1 1 1 0]]

[[0 0 0 0 0]
[0 1 0 0 0]
[0 0 0 0 0]
[0 0 0 0 0]
[0 0 0 0 0]]
... till end

我会给出循环的代码(给你所有的代码没问题,但是它太大了,错误可能是由于我在循环中做了一些事情):

import numpy as np
from time import time

def test(N, p, testTime, length):
assert N>0
x=1
y=1
a=PercolationGrid(N) #this is a class that creates a grid
a.useFixedProbability(p) #the probability that given point will be 1
a.grid[x,y]=1 #I put the starting point as 1 manually
cluster=Cluster(a)
t0=time()
cluster.getCluster(x,y) #this is what I'm testing how fast is it
t1=time()
stats=cluster.getStats() #get the length of cluster and some other data
testTime.append(t1-t0)
testTime.sort()
length.append(stats[1]) #[1] is the length stat that interests me
length.sort() #both sorts are so I can use plot later
print a.getGrid() #show whole grid
clusterGrid=np.zeros(N*N, dtype='int8').reshape(N, N) #create zero grid where I'll "put" the cluster of interest
c1=cluster.getClusterCoordinates() #this is recursive method (if it has any importance)
for xy in c1:
k=xy[0]
m=xy[1]
clusterGrid[k, m]=1
print clusterGrid
del a, cluster, clusterGrid



testTime=[]
length=[]
p=0.59
N=35
np.set_printoptions(threshold='nan') #so the output doesn't shrink
for i in range(10):
test(N, p, testTime, length)

我假设我在释放内存方面做错了什么(如果不是我看不到的循环中的一些微不足道的错误)?我在 64 位 Linux 上使用 python 2.7.3。

编辑:我知道这里的人不应该审查整个代码,而是审查特定的问题,但我找不到发生了什么,唯一的建议是也许我有一些静态变量,但在我看来情况并非如此。所以,如果有人有善意和精力,你可以浏览代码,也许你会看到一些东西。我不久前才开始使用类(class),所以要为很多糟糕的事情做好准备。

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import time

class ProbabilityGrid(object):
"""
This class gives 2D quadratic array (a grid) which is filled with
float values from 0-1, which in many cases represent probabilities
"""

def __init__(self, size=2, dataType='float16'):
"""initialization of a grid with 0. values"""
assert size>1
assert dataType=='float64' or dataType=='float32' or dataType=='float16'
self.n=size
self.dataType=dataType
self.grid=np.zeros((size, size), dtype=dataType)

def getGrid(self):
"""returns a 2D probability array"""
return self.grid

def getSize(self):
"""returns a size of a 2D array"""
return self.size

def fillRandom(self):
"""fills the grid with uniformly random values from 0 to 1"""
n=self.n
self.grid=np.random.rand(n, n)

def fixedProbabilities(self, p):
"""fills the grid with fixed value from 0 to 1"""
assert p<1.0
self.grid=p*np.ones((self.n, self.n))


class PercolationGrid(object):
"""
percolation quadratic grid filled with 1 and 0, int8
which represent a state.
Percolation grid is closly connected to probabilies grid.
ProbabilityGrid gives the starting probabilities will the [i,j] spot
be filled or not. All functions change the PercolationGrid.grid when
ProbabilityGrid.grid changes, so in a way their values are connected
"""
def __init__(self, size=2, dataType='int8'):
"""
initialization of PercolationGrid, sets uniformly 0 and 1 to grid
"""
assert size>1
assert dataType=='int64' or dataType=='int32' or dataType=='int8'
self.n=size
self.dataType=dataType
self.grid=np.zeros((size, size), dtype=dataType)
self.pGrid=ProbabilityGrid(self.n)
self.pGrid.fillRandom()
self.useProbabilityGrid()

#def fillRandom(self, min=0, max=1, distribution='uniform'):
# n=self.n
# self.grid=np.random.random_integers(min, max, n*n).reshape(n, n)

def getGrid(self):
"""returns a 2D percolation array"""
return self.grid

def useProbabilityGrid(self): #use probability grid to get Percolation grid of 0s and 1es
"""
this method fills the PercolationGrid.grid according to probabilities
from Probability.grid
"""
comparisonGrid=np.random.rand(self.n, self.n)
self.grid=np.array(np.floor(self.pGrid.grid-comparisonGrid)+1, dtype=self.dataType)
# Here I used a trick. To simulate whether 1 will apear with probability p,
# we can use uniform random generator which returns values from 0 to 1. If
# the value<p then we get 1, if value>p it's 0.
# But instead looping over each element, it's much faster to make same sized
# grid of random, uniform values from 0 to 1, calculate the difference, add 1
# and use floor function which round everything larger than 1 to 1, and lower
# to 0. Then value-p+1 will give 0 if value<p, 1 if value>p. The result is
# converted to data type of percolation array.

def useFixedProbability(self, p):
"""
this method fills the PercolationGrid according to fixed probabilities
of being filled, for example, a large grid with parameter p set to 0.33
should, aproximatly have one third of places filed with ones and 2/3 with 0
"""
self.pGrid.fixedProbabilities(p)
self.useProbabilityGrid()

def probabilityCheck(self):
""" this method checks the number of ones vs number of elements,
good for checking if the filling of a grid was close to probability
we had in mind. Of course, the accuracy is larger as grid size grows.
For smaller grid sizes you can still check the probability by
running the test multiple times.
"""
sum=self.grid.sum()
print float(sum)/float(self.n*self.n)
#this works because values can only be 0 or 1, so the sum/size gives
#the ratio of ones vs size

def setGrid(self, grid):
shape=grid.shape
i,j=shape[0], shape[1]
assert i>1 and j>1
if i!=j:
print ("The grid needs to be NxN shape, N>1")
self.grid=grid

def setProbabilities(self, grid):
shape=grid.shape
i,j=shape[0], shape[1]
assert i>1 and j>1
if i!=j:
print ("The grid needs to be NxN shape, N>1")
self.pGrid.grid=grid
self.useProbabilityGrid()

def showPercolations(self):
fig1=plt.figure()
fig2=plt.figure()
ax1=fig1.add_subplot(111)
ax2=fig2.add_subplot(111)
myColors=[(1.0, 1.0, 1.0, 1.0), (1.0, 0.0, 0.0, 1.0)]
mycmap=mpl.colors.ListedColormap(myColors)

subplt1=ax1.matshow(self.pGrid.grid, cmap='jet')
cbar1=fig1.colorbar(subplt1)

subplt2=ax2.matshow(self.grid, cmap=mycmap)
cbar2=fig2.colorbar(subplt2, ticks=[0.25,0.75])
cbar2.ax.set_yticklabels(['None', 'Percolated'], rotation='vertical')

class Cluster(object):
"""This is a class of percolation clusters"""
def __init__(self, array):
self.grid=array.getGrid()
self.N=len(self.grid[0,])
self.cluster={}
self.numOfSteps=0

#next 4 functions return True if field next to given field is 1 or False if it's 0
def moveLeft(self, i, j):
moveLeft=False
assert i<self.N
assert j<self.N
if j>0 and self.grid[i, j-1]==1:
moveLeft=True
return moveLeft

def moveRight(self, i, j):
moveRight=False
assert i<self.N
assert j<self.N
if j<N-1 and self.grid[i, j+1]==1:
moveRight=True
return moveRight

def moveDown(self, i, j):
moveDown=False
assert i<self.N
assert j<self.N
if i<N-1 and self.grid[i+1, j]==1:
moveDown=True
return moveDown

def moveUp(self, i, j):
moveUp=False
assert i<self.N
assert j<self.N
if i>0 and self.grid[i-1, j]==1:
moveUp=True
return moveUp

def listOfOnes(self):
"""nested list of connected ones in each row"""

outlist=[]

for i in xrange(self.N):
outlist.append([])
helplist=[]
for j in xrange(self.N):
if self.grid[i, j]==0:
if (j>0 and self.grid[i, j-1]==0) or (j==0 and self.grid[i, j]==0):
continue # condition needed because of edges
outlist[i].append(helplist)
helplist=[]
continue
helplist.append((i, j))
if self.grid[i, j]==1 and j==self.N-1:
outlist[i].append(helplist)
return outlist

def getCluster(self, i=0, j=0, moveD=[1, 1, 1, 1]):
#(left, right, up, down)
#moveD short for moveDirections, 1 means that it tries to move it to that side, 0 so it doesn't try
self.numOfSteps=self.numOfSteps+1
if self.grid[i, j]==1:
self.cluster[(i, j)]=True
else:
print "the starting coordinate is not in any cluster"
return
if moveD[0]==1:
try: #if it comes to same point from different directions we'd get an infinite recursion, checking if it already been on that point prevents that
self.cluster[(i, j-1)]
moveD[0]=0
except:
if self.moveLeft(i, j)==False: #check if 0 or 1 is left to (i, j)
moveD[0]=0
else:
self.getCluster(i, j-1, [1, 0, 1, 1]) #right is 0, because we came from left
if moveD[1]==1:
try:
self.cluster[(i, j+1)]
moveD[1]=0
except:
if self.moveRight(i, j)==False:
moveD[1]=0
else:
self.getCluster(i, j+1, [0, 1, 1, 1])
if moveD[2]==1:
try:
self.cluster[(i-1, j)]
moveD[2]=0
except:
if self.moveUp(i, j)==False:
moveD[2]=0
else:
self.getCluster(i-1, j, [1, 1, 1, 0])
if moveD[3]==1:
try:
self.cluster[(i+1, j)]
moveD[3]=0
except:
if self.moveDown(i, j)==False:
moveD[3]=0
else:
self.getCluster(i+1, j, [1, 1, 0, 1])
if moveD==(0, 0, 0, 0):
return

def getClusterCoordinates(self):
return self.cluster

def getStats(self):
print "Number of recursions:", self.numOfSteps
print "Length of cluster:", len(self.cluster)
return (self.numOfSteps, len(self.cluster))

最佳答案

您的错误来自 getCluster 方法。将 moveD 设置为 [1,1,1,1] 时,您实际上是在设置一个静态变量(不要在此引用我的话)。这导致先前执行的信息得以延续。

Here is a link to a blog post that shows an example of this.

下面是 getCluster 方法的工作版本,它既修复了默认争论问题,又删除了表现出问题行为的无关 moveD 分配。

def getCluster(self, i=0, j=0, moveD=None):
#(left, right, up, down)
#moveD short for moveDirections, 1 means that it tries to move it to that side, 0 so it doesn't try
if moveD == None: moveD = [1, 1, 1, 1]
self.numOfSteps=self.numOfSteps+1
if self.grid[i, j]==1:
self.cluster[(i, j)]=True
else:
print "the starting coordinate is not in any cluster"
return
if moveD[0]==1:
try: #if it comes to same point from different directions we'd get an infinite recursion, checking if it already been on that point prevents that
self.cluster[(i, j-1)]
except:
if self.moveLeft(i, j)==True: #check if 0 or 1 is left to (i, j)
self.getCluster(i, j-1, [1, 0, 1, 1]) #right is 0, because we came from left
if moveD[1]==1:
try:
self.cluster[(i, j+1)]
except:
if self.moveRight(i, j)==True:
self.getCluster(i, j+1, [0, 1, 1, 1])
if moveD[2]==1:
try:
self.cluster[(i-1, j)]
except:
if self.moveUp(i, j)==True:
self.getCluster(i-1, j, [1, 1, 1, 0])
if moveD[3]==1:
try:
self.cluster[(i+1, j)]
except:
if self.moveDown(i, j)==True:
self.getCluster(i+1, j, [1, 1, 0, 1])

关于python - 一条一条运行时效果不错,循环使用时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10759353/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com