3D中更有效的自回避自由连接链



我正在尝试创建一个简单的自回避自由连接链。链部分已经完成,它从三维空间中的给定点开始(例如[0,0,0](。然后,我通过随机化两个球面坐标θ,φ(给定半径(来生成一个新点。给我一个新的观点。

由于这些点是随机放置的(与三维网格上正常三维行走的整数相反(,我无法检查准确的点以前是否被访问过(即,在访问点的数组上迭代(。相反,我必须检查该点是否位于先前访问的点(每个访问点创建的小球体(的特定半径内。

我尝试提取代码中需要帮助的部分,并对其进行了调整,使其能够自行运行。这具有步长1;避免半径"=0.5(任意选择(

import numpy as np
import random
# Generating new point in spherical coordinates, convert to cartesian coordinates
steps = 10
visited = np.zeros([steps,3],dtype=float) # "array of all visited points"
steplength= 1
costheta = random.uniform(-1,1)
theta = np.arccos(costheta)
phi = random.random() * 2 * np.pi
newpos = numpy.copy(visited[-1]) # copy of "previous point"
newpos[0] += steplength* np.cos(phi) * np.sin(theta)
newpos[1] += steplength* np.sin(phi) * np.sin(theta)
newpos[2] += steplength* np.cos(theta)
# Self-avoid condition (part I need help with)
tooclose = False
for i in range(steps): #For every visited position, check if newpos is too close
diff = np.subtract(pos, self.visited[i])
dist = np.sqrt(diff.dot(diff))
if dist < avoidradius ** 2:
tooclose = True
break

如代码所示,我只需检查与每个点的距离,并检查它是否小于允许的半径。这种方法的作用是使其";"自我回避";,但速度很慢。有更好的方法吗?也许使用不同的坐标系、不同的numpy代码(我不太擅长numpy(、不同的库或完全不同的设置?

这里是您的代码示例的一个经过更正并稍微扩展(初始化(的版本。矢量化循环附加在底部。

注意:numpy的矢量化总是意味着:注意任何for循环-->把他们赶走。

关于你的问题有几点。由于在for循环方法中,只要找到if的解决方案,就会中断,因此性能在很大程度上取决于何时找到解决方案。由于在随机行走的情况下,这很可能是最后一个条目之一,因此最好反转循环(从末尾开始(。试试你自己。

矢量化的代码从不中断,它总是完成所有的计算——但速度极快。

import numpy as np
# Generating new point in spherical coordinates, convert to cartesian coordinates
steps = 100
visited = np.zeros([steps,3], dtype=float) # "array of all visited points"
steplength = 1.
avoidradius = 1
# fill points
for iPoint in range(steps):
costheta = np.random.uniform(-1,1)
theta = np.arccos(costheta)
phi = np.random.random() * 2 * np.pi
visited[iPoint,0] = visited[iPoint-1,0] + steplength* np.cos(phi) * np.sin(theta)
visited[iPoint,1] = visited[iPoint-1,1] + steplength* np.sin(phi) * np.sin(theta)
visited[iPoint,2] = visited[iPoint-1,2] + steplength* np.cos(theta)

# "new" point
costheta = np.random.uniform(-1,1)
theta = np.arccos(costheta)
phi = np.random.random() * 2 * np.pi
newpos = np.array(visited[-1])
newpos[0] += steplength * np.cos(phi) * np.sin(theta)
newpos[1] += steplength * np.sin(phi) * np.sin(theta)
newpos[2] += steplength * np.cos(theta)
# your solution
# %%timeit # use this in jupyter lab
# Self-avoid condition (part I need help with)
tooclose = False
for iPoint in range(steps): # For every visited position, check if newpos is too close
diff = np.subtract(newpos, visited[iPoint])
dist = diff.dot(diff)
if dist < avoidradius**2:
tooclose = True
break

# vectorized solution    
# %%timeit # use this in jupyter lab
dist = (visited - newpos)**2
isclose = np.sum(dist, axis=1) < avoidradius**2
tooclose = np.count_nonzero(isclose) > 0

你可以把它粘贴到jupyter实验室并运行一些测试,我做了:

对于步骤=10

您的版本:

每个环路14.7µs±360 ns(7次运行的平均值±标准偏差,每次100000个环路(

矢量化版本:

每个环路8.68µs±212 ns(7次运行的平均值±标准偏差,每次100000个环路(

对于步骤=100

您的版本:

每个环路143µs±5.36µs(7次运行的平均值±标准偏差,每次10000个环路(

矢量化版本:

每个环路11.1µs±152 ns(7次运行的平均值±标准偏差,每次100000个环路(

因此,你看,对于小n,基本上无关紧要。对于大的n,矢量化的循环几乎不会变慢,而For循环则变得超级慢。

最新更新