@@ -175,7 +175,7 @@ maze. First task is thus to build a maze.
175175 :class: legend
176176
177177 A hedge maze at Longleat stately home in England.
178- ( Image by `Prince Rurik <https://commons.wikimedia.org/wiki/File:Longleat_maze.jpg >`_) , 2005.
178+ Image by `Prince Rurik <https://commons.wikimedia.org/wiki/File:Longleat_maze.jpg >`_, 2005.
179179
180180.. image :: ../data//Longleat-maze-cropped.jpg
181181 :width: 100%
@@ -329,7 +329,10 @@ path in a graph using a diffusion process. Optimal path is found by ascending
329329the resulting gradient. This algorithm runs in quadratic time :math: `O(|V||E|)`
330330(where V is the number of vertices, and E is the number of edges). However, in
331331our simple case, we won't hit the worst case scenario. The algorithm is
332- illustrated below (reading from left to right, top to bottom).
332+ illustrated below (reading from left to right, top to bottom). Once this is
333+ done, we can ascent the gradient from the starting node. You can check on the
334+ figure this leads to the shortest path.
335+
333336
334337.. image :: ../data/value-iteration-1.pdf
335338 :width: 19%
@@ -359,6 +362,61 @@ cell new value is computed as the maximum value between the current cell value
359362and the discounted (gamma=0.9 in the case below) 4 neighbour values. The
360363process start as soon as the starting node value become strictly positive.
361364
365+ The numpy implementation is straightforward and we can take advanage of the
366+ `scipy.ndimage.generic_filter ` for the diffusion process:
367+
368+ .. code :: python
369+
370+ def diffuse (Z ):
371+ # North, West, Center, East, South
372+ return max (gamma* Z[0 ], gamma* Z[1 ], Z[2 ], gamma* Z[3 ], gamma* Z[4 ])
373+
374+ # Build gradient array
375+ G = np.zeros(Z.shape)
376+
377+ # Initialize gradient at the entrance with value 1
378+ G[start] = 1
379+
380+ # Discount factor
381+ gamma = 0.99
382+
383+ # We iterate until value at exit is > 0. This requires the maze
384+ # to have a solution or it will be stuck in the loop.
385+ while G[goal] == 0.0 :
386+ G = Z * generic_filter(G, diffuse, footprint = [[0 , 1 , 0 ],
387+ [1 , 1 , 1 ],
388+ [0 , 1 , 0 ]])
389+
390+ But this is actually slow and it's better to cook-up our own solution, reusing
391+ part of the game of life code:
392+
393+ .. code :: python
394+
395+ # Build gradient array
396+ G = np.zeros(Z.shape)
397+
398+ # Initialize gradient at the entrance with value 1
399+ G[start] = 1
400+
401+ # Discount factor
402+ gamma = 0.99
403+
404+ # We iterate until value at exit is > 0. This requires the maze
405+ # to have a solution or it will be stuck in the loop.
406+ G_gamma = np.empty_like(G)
407+ while G[goal] == 0.0 :
408+ np.multiply(G, gamma, out = G_gamma)
409+ N = G_gamma[0 :- 2 ,1 :- 1 ]
410+ W = G_gamma[1 :- 1 ,0 :- 2 ]
411+ C = G[1 :- 1 ,1 :- 1 ]
412+ E = G_gamma[1 :- 1 ,2 :]
413+ S = G_gamma[2 :,1 :- 1 ]
414+ G[1 :- 1 ,1 :- 1 ] = Z[1 :- 1 ,1 :- 1 ]* np.maximum(N,np.maximum(W,
415+ np.maximum(C,np.maximum(E,S))))
416+
417+ Once this is done, we can ascent the gradient to find the shortest path as
418+ illustrated on the figure below:
419+
362420.. admonition :: **Figure 8**
363421 :class: legend
364422
@@ -375,7 +433,6 @@ Sources
375433+++++++
376434
377435* `maze-build.py <../code/maze-build.py >`_
378- * `maze-python.py <../code/maze-numpy.py >`_
379436* `maze-numpy.py <../code/maze-numpy.py >`_
380437
381438References
0 commit comments