dijkstra_graph 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40d8dfafa22964edb55043f62194663df6ffe708
4
- data.tar.gz: 7c76517bd99090caca0eb6bafb488c147851391f
3
+ metadata.gz: d771e3085a0ffda14a30fc7fa92cf8e69208e984
4
+ data.tar.gz: 315da882ae3971d9c9a92e92755812074b5d4f3c
5
5
  SHA512:
6
- metadata.gz: 06cd0b89391979779f79bca07e34d8ea6e4917249d9d7d3a748f9c7843859e7b83acf6d6d248cc405e6a9683f3d3fbd5cbafb9283c4d5b8b626c483adf99cecf
7
- data.tar.gz: 610fce885958f2aa28ae069448368fb080df6a24f74ab265d955b2d4739e4c281ea83bb5e13df4ca877c673979b7ed1bccba276c0fb08ce4517c9ac4092a2bbd
6
+ metadata.gz: 5b0ceec8d23b964237a72e57ddcf3697300dbf755910a5ba3a459e36a0860e7cdd5818a2f8eeb8cef34bd3185b45cd9ca0aad47c145d29c1bd761cbf01b096c9
7
+ data.tar.gz: 5917752b4b7fefdf63a149b6d70c2d4e7134b21de7621d0bfc49e8992e017eb23a1423f75ae47d6c3ee27021b487a3e76b79bfda3d866dc5fac4d92b7f9df0bc
@@ -1,4 +1,4 @@
1
- Style/BlockLength:
1
+ Metrics/BlockLength:
2
2
  Exclude:
3
3
  - 'dijkstra_graph.gemspec'
4
4
  - 'Rakefile'
data/README.md CHANGED
@@ -32,25 +32,71 @@ get_edge_weight(source, destination)
32
32
  get_adjacent_vertices(source)
33
33
 
34
34
  # Use Dijkstra's algorithm to find the shortest distances
35
- # from the start vertex to each of the other vertices
35
+ # from the source vertex to each of the other vertices
36
36
  #
37
- # Returns a hash of form { 'start' => 0, 'a' => 3, 'b' => 4 },
38
- # where result[v] indicates the shortest distance from start to v
39
- shortest_distances(start)
37
+ # Returns a hash of form { 'source' => 0, 'a' => 3, 'b' => 4 },
38
+ # where result[v] indicates the shortest distance from source to v
39
+ shortest_distances(source)
40
40
 
41
41
  # Use Dijkstra's algorithm to find the shortest paths
42
- # from the start vertex to each of the other vertices
42
+ # from the source vertex to each of the other vertices
43
43
  #
44
44
  # Returns a hash of form { 'c' => ['a', 'b', 'c'] }, where
45
- # result[v] indicates the shortest path from start to v
46
- shortest_paths(start)
45
+ # result[v] indicates the shortest path from source to v
46
+ shortest_paths(source)
47
+
48
+ # Use Dijkstra's algorithm to find the shortest paths
49
+ # from the source vertex to vertices within a given radius
50
+ #
51
+ # Returns a hash of form { 'c' => ['a', 'b', 'c'] }, where
52
+ # result[v] indicates the shortest path from source to v
53
+ shortest_paths_in_radius(source, radius)
47
54
 
48
55
  # Use Dijkstra's algorithm to find the shortest path
49
- # from the start vertex to the destination vertex
56
+ # from the source vertex to the destination vertex
50
57
  #
51
58
  # Returns an array of vertices along the shortest path
52
59
  # of form ['a', 'b', 'c'], or [] if no such path exists
53
- shortest_path(start, destination)
60
+ shortest_path(source, destination)
61
+ ```
62
+
63
+ ## Installation
64
+
65
+ Add this line to your application's Gemfile:
66
+
67
+ ```ruby
68
+ gem 'dijkstra_graph'
69
+ ```
70
+
71
+ Then you can require the gem in Ruby programs:
72
+
73
+ ```ruby
74
+ require 'dijkstra_graph'
75
+
76
+ graph = DijkstraGraph::Graph.new
77
+ graph.add_undirected_edge('Burnaby', 'Vancouver', 10)
78
+ graph.add_edge('Burnaby', 'Port Coquitlam', 23)
79
+ graph.add_edge('Vancouver', 'Langley', 37)
80
+ graph.add_undirected_edge('Langley', 'Port Coquitlam', 35)
81
+ shortest_paths_from_vancouver = graph.shortest_paths('Vancouver')
82
+
83
+ # => { 'Burnaby' => ['Vancouver', 'Burnaby'],
84
+ # 'Langley' => ['Vancouver', 'Langley'],
85
+ # 'Port Coquitlam' => ['Vancouver', 'Burnaby', 'Port Coquitlam'] }
86
+
87
+ van_paths_within_35k = graph.shortest_paths_in_radius('Vancouver', 35)
88
+
89
+ # => { 'Burnaby' => ['Vancouver', 'Burnaby'],
90
+ # 'Port Coquitlam' => ['Vancouver', 'Burnaby', 'Port Coquitlam'] }
91
+
92
+ van_to_portco_path = graph.shortest_path('Vancouver', 'Port Coquitlam')
93
+
94
+ # => ['Vancouver', 'Burnaby', 'Port Coquitlam']
95
+
96
+ distances_from_vancouver = graph.shortest_distances('Vancouver')
97
+
98
+ # => { 'Vancouver' => 0, 'Burnaby' => 10,
99
+ # 'Langley' => 37, 'Port Coquitlam' => 33 }
54
100
  ```
55
101
 
56
102
  ## Development
@@ -63,4 +109,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/msayso
63
109
 
64
110
  ## License
65
111
 
66
- The weighted_graph library is open source and available under the terms of the [MIT License](http://opensource.org/licenses/MIT).
112
+ The dijkstra_graph library is open source and available under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -13,7 +13,7 @@ module DijkstraGraph
13
13
  # Vertices 'to-visit' are stored in a priority queue that
14
14
  # uses a Fibonacci heap to give O(1) insert, amortized O(1)
15
15
  # decrease_priority, and amortized O(log n) delete_min.
16
- # Priority represents path distance from the start vertex.
16
+ # Priority represents path distance from the source vertex.
17
17
  #
18
18
  # The shortest distances found so far to each vertex are
19
19
  # stored in a simple hash which gives O(1) read/write.
@@ -24,13 +24,13 @@ module DijkstraGraph
24
24
  end
25
25
 
26
26
  # Use Dijkstra's algorithm to find the shortest distances
27
- # from the start vertex to each of the other vertices
27
+ # from the source vertex to each of the other vertices
28
28
  #
29
- # Returns a hash of form { 'start' => 0, 'a' => 3, 'b' => 4 },
30
- # where result[v] indicates the shortest distance from start to v
31
- def shortest_distances(start)
29
+ # Returns a hash of form { 'source' => 0, 'a' => 3, 'b' => 4 },
30
+ # where result[v] indicates the shortest distance from source to v
31
+ def shortest_distances(source)
32
32
  distances = Hash.new { Float::INFINITY } # Initial distances = Inf
33
- queue = initialize_queue(start) # Begin at start node
33
+ queue = initialize_queue(source) # Begin at source node
34
34
  until queue.empty?
35
35
  v, distances[v] = queue.delete_min # Visit next closest vertex
36
36
  update_distances_to_neighbours(v, distances, queue) # Update neighbours
@@ -39,69 +39,108 @@ module DijkstraGraph
39
39
  end
40
40
 
41
41
  # Use Dijkstra's algorithm to find the shortest paths
42
- # from the start vertex to each of the other vertices
42
+ # from the source vertex to each of the other vertices
43
43
  #
44
44
  # Returns a hash of form { 'c' => ['a', 'b', 'c'] }, where
45
- # result[v] indicates the shortest path from start to v
46
- def shortest_paths(start)
45
+ # result[v] indicates the shortest path from source to v
46
+ def shortest_paths(source)
47
47
  predecessors = {} # Initialize vertex predecessors
48
48
  distances = Hash.new { Float::INFINITY } # Initialize distances to Inf
49
- queue = initialize_queue(start) # Initialize queue with start
49
+ queue = initialize_queue(source) # Initialize queue with source
50
50
  until queue.empty?
51
51
  # Visit next closest vertex and update neighbours
52
52
  v, distances[v] = queue.delete_min
53
- update_paths_to_neighbours(v, predecessors, distances, queue)
53
+ update_paths_to_neighbours(v, distances, queue, predecessors)
54
54
  end
55
- PathUtil.path_arrays(predecessors, start)
55
+ PathUtil.path_arrays(predecessors, source)
56
+ end
57
+
58
+ # Use Dijkstra's algorithm to find the shortest paths
59
+ # from the source vertex to vertices within a given radius
60
+ #
61
+ # Returns a hash of form { 'c' => ['a', 'b', 'c'] }, where
62
+ # result[v] indicates the shortest path from source to v
63
+ def shortest_paths_in_radius(source, radius)
64
+ predecessors = {} # Initialize vertex predecessors
65
+ distances = Hash.new { Float::INFINITY } # Initialize distances to Inf
66
+ queue = initialize_queue(source) # Initialize queue with source
67
+ until queue.empty?
68
+ # Visit next closest vertex and update neighbours
69
+ v, distance = queue.delete_min
70
+ return PathUtil.path_arrays(predecessors, source) if distance > radius
71
+ distances[v] = distance
72
+ update_neighbours_in_radius(v, distances, queue, predecessors, radius)
73
+ end
74
+ PathUtil.path_arrays(predecessors, source)
56
75
  end
57
76
 
58
77
  # Use Dijkstra's algorithm to find the shortest path
59
- # from the start vertex to the destination vertex
78
+ # from the source vertex to the destination vertex
60
79
  #
61
80
  # Returns an array of vertices along the shortest path
62
81
  # of form ['a', 'b', 'c'], or [] if no such path exists
63
- def shortest_path(start, dest)
82
+ def shortest_path(source, dest)
64
83
  predecessors = {} # Initialize vertex predecessors
65
84
  distances = Hash.new { Float::INFINITY } # Initialize distances to Inf
66
- queue = initialize_queue(start) # Initialize queue with start
85
+ queue = initialize_queue(source) # Initialize queue with source
67
86
  until queue.empty?
68
87
  v, distances[v] = queue.delete_min # Visit next closest node
69
- return PathUtil.path_array(predecessors, start, dest) if v == dest
70
- update_paths_to_neighbours(v, predecessors, distances, queue)
88
+ return PathUtil.path_array(predecessors, source, dest) if v == dest
89
+ update_paths_to_neighbours(v, distances, queue, predecessors)
71
90
  end
72
- [] # No path found from start to dest
91
+ [] # No path found from source to dest
73
92
  end
74
93
 
75
94
  private
76
95
 
77
- # Initialize priority queue with start vertex at distance = 0
78
- def initialize_queue(start_vertex)
96
+ # Initialize priority queue with source vertex at distance = 0
97
+ def initialize_queue(source_vertex)
79
98
  queue = PriorityQueue.new
80
- queue[start_vertex] = 0
99
+ queue[source_vertex] = 0
81
100
  queue
82
101
  end
83
102
 
84
103
  # Update distances to neighbours of v and queue changed neighbours
85
104
  def update_distances_to_neighbours(v, distances, queue)
86
- distance_v = distances[v]
87
- get_adjacent_vertices(v).each do |w|
88
- distance_through_v = distance_v + get_edge_weight(v, w)
89
- if distance_through_v < distances[w]
90
- queue[w] = distances[w] = distance_through_v
91
- end
92
- end
105
+ update_neighbours(v, distances, method(:update_distance),
106
+ distances: distances, queue: queue)
93
107
  end
94
108
 
95
109
  # Update paths to neighbours of v and queue changed neighbours
96
- def update_paths_to_neighbours(v, predecessors, distances, queue)
110
+ def update_paths_to_neighbours(v, distances, queue, predecessors)
111
+ update_neighbours(v, distances, method(:update_path),
112
+ distances: distances, queue: queue,
113
+ predecessors: predecessors, predecessor: v)
114
+ end
115
+
116
+ # Update paths to neighbours of v in radius and queue changed neighbours
117
+ def update_neighbours_in_radius(v, distances, queue, predecessors, radius)
118
+ update_neighbours(v, distances, method(:update_path),
119
+ distances: distances, queue: queue, radius: radius,
120
+ predecessors: predecessors, predecessor: v)
121
+ end
122
+
123
+ # Apply given method to each neighbour we find a shorter path to
124
+ def update_neighbours(v, distances, update_method, update_params)
97
125
  distance_v = distances[v]
98
126
  get_adjacent_vertices(v).each do |w|
99
127
  distance_through_v = distance_v + get_edge_weight(v, w)
100
128
  if distance_through_v < distances[w]
101
- queue[w] = distances[w] = distance_through_v
102
- predecessors[w] = v
129
+ update_method.call(w, distance_through_v, update_params)
103
130
  end
104
131
  end
105
132
  end
133
+
134
+ # Update shortest distance to vertex
135
+ def update_distance(vertex, distance, params)
136
+ params[:queue][vertex] = params[:distances][vertex] = distance
137
+ end
138
+
139
+ # Update shortest path to vertex
140
+ def update_path(vertex, distance, params)
141
+ return if params[:radius] && distance > params[:radius]
142
+ update_distance(vertex, distance, params)
143
+ params[:predecessors][vertex] = params[:predecessor]
144
+ end
106
145
  end
107
146
  end
@@ -1,3 +1,3 @@
1
1
  module DijkstraGraph
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.1.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dijkstra_graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Sayson