xmd79

MathSearchDijkstra

Oct 8th, 2021
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.76 KB | None | 0 0
  1. // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
  2. // © RicardoSantos
  3.  
  4. //@version=5
  5.  
  6. // @description Shortest Path Tree Search Methods using Dijkstra Algorithm.
  7. library("MathSearchDijkstra")
  8.  
  9. // reference:
  10. // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
  11. // https://blog.quantinsti.com/dijkstra-algorithm/
  12. // https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
  13. // possible future implementation? multiple point search: https://iopscience.iop.org/article/10.1088/1742-6596/1530/1/012040/pdf
  14.  
  15. import RicardoSantos/ArrayExtension/1 as ae
  16.  
  17. // @function Find the lowest cost/distance.
  18. // @param distances float array, data set with distance costs to start index.
  19. // @param flagged_vertices bool array, data set with visited vertices flags.
  20. // @returns int, lowest cost/distance index.
  21. export min_distance (int[] distances, bool[] flagged_vertices) => //{
  22. int _size_d = array.size(distances)
  23. int _size_v = array.size(flagged_vertices)
  24. if _size_d < 1
  25. runtime.error('MathSearchDijkstra -> min_distance(): "distances" has the wrong size.')
  26. int(na)
  27. else if _size_d != _size_v
  28. runtime.error('MathSearchDijkstra -> min_distance(): "distances" and "flagged_vertices" size does not match.')
  29. int(na)
  30. else
  31. // int __MAXINT__ = 9223372036854776000 // props to @XelArjona!!
  32. // Initialize min value
  33. int _min = 9223372036854776000
  34. int _min_index = -1
  35. for _i = 0 to _size_d - 1
  36. int _d = array.get(distances, _i)
  37. if (not array.get(flagged_vertices, _i)) and _d <= _min
  38. _min := _d
  39. _min_index := _i
  40. _min_index
  41. //{ usage:
  42. //{ remarks:
  43. //}}}
  44.  
  45. // @function Dijkstra Algorithm, perform a greedy tree search to calculate the cost/distance to selected start node at each vertex.
  46. // @param matrix_graph int array, matrix holding the graph adjacency list and costs/distances.
  47. // @param dim_x int, x dimension of matrix_graph.
  48. // @param dim_y int, y dimension of matrix_graph.
  49. // @param start int, the vertex index to start search.
  50. // @returns int array, set with costs/distances to each vertex from start vertexs.
  51. export dijkstra (int[] matrix_graph, int dim_x, int dim_y, int start) => //{
  52. // int __MAXINT__ = 9223372036854776000 // props to @XelArjona!!
  53. int _size_m = array.size(matrix_graph)
  54. if _size_m < 2
  55. runtime.error('MathSearchDijkstra -> search(): "matrix_graph" has the wrong size.')
  56. array.new_int(na)
  57. if _size_m != (dim_x * dim_y)
  58. runtime.error('MathSearchDijkstra -> search(): dimensions and size does not match.')
  59. array.new_int(na)
  60. else
  61. int[] _distances = array.new_int(dim_x, 9223372036854776000)
  62. bool[] _visited = array.new_bool(dim_x, false)
  63.  
  64. array.set(_distances, start, 0)
  65. for _i = 0 to dim_x-1
  66. int _nearest_index = min_distance(_distances, _visited)
  67. array.set(_visited, _nearest_index, true)
  68. for _v = 0 to dim_x-1
  69. bool _is_visited = array.get(_visited, _v)
  70. if (not _is_visited)
  71. int _distance_between = array.get(matrix_graph, ae.index_2d_to_1d(dim_x, dim_y, _nearest_index, _v))
  72. if (_distance_between != 0)
  73. int _distance_to_nearest = array.get(_distances, _nearest_index)
  74. int _distance_to_current = array.get(_distances, _v)
  75. int _tentative_sum = _distance_to_nearest + _distance_between
  76. if (_distance_to_nearest != 9223372036854776000) and (_tentative_sum < _distance_to_current)
  77. array.set(_distances, _v, _tentative_sum)
  78. _distances
  79. //{ usage:
  80. //{ remarks:
  81. //}}}
  82.  
  83. // @function Retrieves the shortest path between 2 vertices in a graph using Dijkstra Algorithm.
  84. // @param start int, the vertex index to start search.
  85. // @param end int, the vertex index to end search.
  86. // @param matrix_graph int array, matrix holding the graph adjacency list and costs/distances.
  87. // @param dim_x int, x dimension of matrix_graph.
  88. // @param dim_y int, y dimension of matrix_graph.
  89. // @returns int array, set with vertex indices to the shortest path.
  90. export shortest_path (int start, int end, int[] matrix_graph, int dim_x, int dim_y) => //{
  91. // start + end + array.size(matrix_graph) + dim_x + dim_y // just to use all param..
  92. int _size_m = array.size(matrix_graph)
  93.  
  94. int[] _distances = dijkstra (matrix_graph, dim_x, dim_y, start)
  95. int[] _path = array.new_int(1, end)
  96. // build path backwards with the least cost:
  97. // 1: end vertex
  98. // 2: check adjacent vertex sum + edge cost to current vertex,
  99. // 3: if its smaller or equal add it to path, else skip
  100. // 4: repeat.
  101. _current_vertex = end
  102. while _current_vertex != start
  103. for _i = 0 to dim_x - 1
  104. _vi = array.get(matrix_graph, ae.index_2d_to_1d(dim_x, dim_y, _current_vertex, _i))
  105. if _vi != 0
  106. _di = array.get(_distances, _i)
  107. if _di + _vi <= array.get(_distances, _current_vertex)
  108. array.unshift(_path, _i)
  109. _current_vertex := _i
  110. _path
  111. //{ usage:
  112. //{ remarks:
  113. //}}}
  114.  
  115. int n_vertices = 9
  116. // adjacency list matrix:
  117. var int[] graph = array.from( 0, 4, 0, 0, 0, 0, 0, 8, 0,
  118. 4, 0, 8, 0, 0, 0, 0, 11, 0,
  119. 0, 8, 0, 7, 0, 4, 0, 0, 2,
  120. 0, 0, 7, 0, 9, 14, 0, 0, 0,
  121. 0, 0, 0, 9, 0, 10, 0, 0, 0,
  122. 0, 0, 4, 14, 10, 0, 2, 0, 0,
  123. 0, 0, 0, 0, 0, 2, 0, 1, 6,
  124. 8, 11, 0, 0, 0, 0, 1, 0, 7,
  125. 0, 0, 2, 0, 0, 0, 6, 7, 0)
  126.  
  127. int start = input.int(defval=0, minval=0, maxval=n_vertices)
  128. int end = input.int(defval=8, minval=0, maxval=n_vertices)
  129.  
  130. var int[] dist = dijkstra(graph, n_vertices, n_vertices, start)
  131. var int[] path = shortest_path(start, end, graph, n_vertices, n_vertices)
  132. var int[] indices = array.from(0,1,2,3,4,5,6,7,8)
  133. var label legend = label.new(bar_index, 0.0, str.format('index:{0}\ncosts:{1}\npath :{2}', str.tostring(indices), str.tostring(dist), str.tostring(path)), style=label.style_label_center, textalign=text.align_left)
  134.  
  135. if barstate.isfirst
  136. // nodes x, y coordinates:
  137. int[] _x = array.from(000, 010, 020, 030, 040, 050, 060, 070, 080)
  138. int[] _y = array.from(180, 160, 000, 020, 020, 160, 020, 180, 000)
  139. for _i = 0 to n_vertices-1
  140. int _nodexi = array.get(_x, _i)
  141. int _nodeyi = array.get(_y, _i)
  142. bool _is_ipath = array.includes(path, _i)
  143. color _col_ispath = _is_ipath ? color.yellow : color.blue
  144. label.new(_nodexi, _nodeyi, '', color=_col_ispath, style=label.style_circle, size=size.large)
  145. label.new(_nodexi, _nodeyi, str.tostring(_i), color=color.new(#000000, 100), style=label.style_label_center, size=size.large, tooltip=str.tostring(array.get(dist, _i)))
  146. for _j = 0 to _i
  147. int _gij = array.get(graph, ae.index_2d_to_1d(n_vertices, n_vertices, _i, _j))
  148. if _gij > 0
  149. int _nodexj = array.get(_x, _j)
  150. int _nodeyj = array.get(_y, _j)
  151. bool _is_jpath = array.includes(path, _j)
  152. if _is_ipath and _is_jpath
  153. line.new(_nodexi, _nodeyi, _nodexj, _nodeyj, color=color.new(color.yellow, 30), width=3)
  154. else
  155. line.new(_nodexi, _nodeyi, _nodexj, _nodeyj, color=color.new(color.gray, 50), width=1)
  156. label.new(int((_nodexi+_nodexj)/2), (_nodeyi+_nodeyj)/2, str.tostring(_gij), color=color.gray, style=label.style_label_center, size=size.normal)
  157.  
  158.  
  159.  
  160.  
  161. //#
Advertisement
Add Comment
Please, Sign In to add comment