python – 使用meshgrid上两点之间的’n`节点计算最短路径
作者:互联网
我在网格上定义了以下3D表面:
%pylab inline
def muller_potential(x, y, use_numpy=False):
"""Muller potential
Parameters
----------
x : {float, np.ndarray, or theano symbolic variable}
X coordinate. If you supply an array, x and y need to be the same shape,
and the potential will be calculated at each (x,y pair)
y : {float, np.ndarray, or theano symbolic variable}
Y coordinate. If you supply an array, x and y need to be the same shape,
and the potential will be calculated at each (x,y pair)
Returns
-------
potential : {float, np.ndarray, or theano symbolic variable}
Potential energy. Will be the same shape as the inputs, x and y.
Reference
---------
Code adapted from https://cims.nyu.edu/~eve2/ztsMueller.m
"""
aa = [-1, -1, -6.5, 0.7]
bb = [0, 0, 11, 0.6]
cc = [-10, -10, -6.5, 0.7]
AA = [-200, -100, -170, 15]
XX = [1, 0, -0.5, -1]
YY = [0, 0.5, 1.5, 1]
# use symbolic algebra if you supply symbolic quantities
exp = np.exp
value = 0
for j in range(0, 4):
if use_numpy:
value += AA[j] * numpy.exp(aa[j] * (x - XX[j])**2 + bb[j] * (x - XX[j]) * (y - YY[j]) + cc[j] * (y - YY[j])**2)
else: # use sympy
value += AA[j] * sympy.exp(aa[j] * (x - XX[j])**2 + bb[j] * (x - XX[j]) * (y - YY[j]) + cc[j] * (y - YY[j])**2)
return value
其中给出了以下情节:
minx=-1.5
maxx=1.2
miny=-0.2
maxy=2
ax=None
grid_width = max(maxx-minx, maxy-miny) / 50.0
xx, yy = np.mgrid[minx : maxx : grid_width, miny : maxy : grid_width]
V = muller_potential(xx, yy, use_numpy=True)
V = ma.masked_array(V, V>200)
contourf(V, 40)
colorbar();
我编写了以下代码来定义该网格上两点之间的最短路径.我在网格网格的两个相邻点之间使用的度量由(V [e] -V [cc])** 2给出,其中cc为当前单元,e为相邻单元之一.邻居定义为完全连接:包括对角线的所有直接邻居.
def dijkstra(V):
mask = V.mask
visit_mask = mask.copy() # mask visited cells
m = numpy.ones_like(V) * numpy.inf
connectivity = [(i,j) for i in [-1, 0, 1] for j in [-1, 0, 1] if (not (i == j == 0))]
cc = unravel_index(V.argmin(), m.shape) # current_cell
m[cc] = 0
P = {} # dictionary of predecessors
#while (~visit_mask).sum() > 0:
for _ in range(V.size):
#print cc
neighbors = [tuple(e) for e in asarray(cc) - connectivity
if e[0] > 0 and e[1] > 0 and e[0] < V.shape[0] and e[1] < V.shape[1]]
neighbors = [ e for e in neighbors if not visit_mask[e] ]
tentative_distance = [(V[e]-V[cc])**2 for e in neighbors]
for i,e in enumerate(neighbors):
d = tentative_distance[i] + m[cc]
if d < m[e]:
m[e] = d
P[e] = cc
visit_mask[cc] = True
m_mask = ma.masked_array(m, visit_mask)
cc = unravel_index(m_mask.argmin(), m.shape)
return m, P
def shortestPath(start, end, P):
Path = []
step = end
while 1:
Path.append(step)
if step == start: break
step = P[step]
Path.reverse()
return asarray(Path)
D, P = dijkstra(V)
path = shortestPath(unravel_index(V.argmin(), V.shape), (40,4), P)
结果如下:
contourf(V, 40)
plot(path[:,1], path[:,0], 'r.-')
路径长度为112:
print path.shape[0]
112
我想知道是否可以计算精确长度n的开始和结束之间的最短路径,其中n是给函数赋予的参数.
备注:如果我将使用的度量值从(V [e] -V [cc])** 2更改为V [e] -V [cc],这会增加负距离,我会获得看起来更好的图,因为它通过本地最低预期:
解决方法:
由于我想获得一个合理的路径,即潜在的样本盆,我写了下面的函数.为了完整性,我记得我写的dijkstra函数:
%pylab
def dijkstra(V, start):
mask = V.mask
visit_mask = mask.copy() # mask visited cells
m = numpy.ones_like(V) * numpy.inf
connectivity = [(i,j) for i in [-1, 0, 1] for j in [-1, 0, 1] if (not (i == j == 0))]
cc = start # current_cell
m[cc] = 0
P = {} # dictionary of predecessors
#while (~visit_mask).sum() > 0:
for _ in range(V.size):
#print cc
neighbors = [tuple(e) for e in asarray(cc) - connectivity
if e[0] > 0 and e[1] > 0 and e[0] < V.shape[0] and e[1] < V.shape[1]]
neighbors = [ e for e in neighbors if not visit_mask[e] ]
t.ntative_distance = asarray([V[e]-V[cc] for e in neighbors])
for i,e in enumerate(neighbors):
d = tentative_distance[i] + m[cc]
if d < m[e]:
m[e] = d
P[e] = cc
visit_mask[cc] = True
m_mask = ma.masked_array(m, visit_mask)
cc = unravel_index(m_mask.argmin(), m.shape)
return m, P
start, end = unravel_index(V.argmin(), V.shape), (40,4)
D, P = dijkstra(V, start)
def shortestPath(start, end, P):
Path = []
step = end
while 1:
Path.append(step)
if step == start: break
step = P[step]
Path.reverse()
return asarray(Path)
path = shortestPath(start, end, P)
其中给出了以下情节:
contourf(V, 40)
plot(path[:,1], path[:,0], 'r.-')
colorbar()
然后,extend_path函数背后的基本思想是扩展通过获取路径中最小化潜力的节点的邻居而获得的最短路径.集合记录在扩展过程中已访问过的单元格.
def get_neighbors(cc, V, visited_nodes):
connectivity = [(i,j) for i in [-1, 0, 1] for j in [-1, 0, 1] if (not (i == j == 0))]
neighbors = [tuple(e) for e in asarray(cc) - connectivity
if e[0] > 0 and e[1] > 0 and e[0] < V.shape[0] and e[1] < V.shape[1]]
neighbors = [ e for e in neighbors if e not in visited_nodes ]
return neighbors
def extend_path(V, path, n):
"""
Extend the given path with n steps
"""
path = [tuple(e) for e in path]
visited_nodes = set()
for _ in range(n):
visited_nodes.update(path)
dist_min = numpy.inf
for i_cc, cc in enumerate(path[:-1]):
neighbors = get_neighbors(cc, V, visited_nodes)
next_step = path[i_cc+1]
next_neighbors = get_neighbors(next_step, V, visited_nodes)
join_neighbors = list(set(neighbors) & set(next_neighbors))
if len(join_neighbors) > 0:
tentative_distance = [ V[e] for e in join_neighbors ]
argmin_dist = argmin(tentative_distance)
if tentative_distance[argmin_dist] < dist_min:
dist_min, new_step, new_step_index = tentative_distance[argmin_dist], join_neighbors[argmin_dist], i_cc+1
path.insert(new_step_index, new_step)
return path
下面是我通过250步扩展最短路径获得的结果:
path_ext = extend_path(V, path, 250)
print len(path), len(path_ext)
path_ext = numpy.asarray(path_ext)
contourf(V, 40)
plot(path[:,1], path[:,0], 'w.-')
plot(path_ext[:,1], path_ext[:,0], 'r.-')
colorbar()
正如预期的那样,当我增加n时,我首先开始对更深的盆地进行采样,如下所示:
rcParams['figure.figsize'] = 14,8
for i_plot, n in enumerate(range(0,250,42)):
path_ext = numpy.asarray(extend_path(V, path, n))
subplot('23%d'%(i_plot+1))
contourf(V, 40)
plot(path_ext[:,1], path_ext[:,0], 'r.-')
title('%d path steps'%len(path_ext))
标签:python,numpy,shortest-path 来源: https://codeday.me/bug/20190706/1394112.html