dijkstra_fast 1.4.2 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,8 +24,10 @@ module DijkstraFast
24
24
  ##
25
25
  class Graph
26
26
 
27
+ include DijkstraFast::ShortestPath
28
+
27
29
  def initialize
28
- @nodes = {}
30
+ @edges = {}
29
31
  end
30
32
 
31
33
  # Adds a weighted edge to the graph. This represents a possible path from the
@@ -36,27 +38,15 @@ module DijkstraFast
36
38
  # If not provided, a default distance of `1` is used.
37
39
  # @return [nil]
38
40
  def add(source, dest, distance: 1)
39
- _add_edge(node(source), node(dest), distance) unless source == dest
40
- end
41
+ return if source == dest
41
42
 
42
- # Finds the shortest path between items, returning both the path as well as
43
- # the total distance travelled.
44
- # @param source [Object] Any Ruby object that represents the source item
45
- # @param dest [Object] Any Ruby object that represents the destination item
46
- # @return [BestPath]
47
- def shortest_path(source, dest)
48
- best_path = BestPath.new
49
- best_path.distance = _shortest_path(node(source), node(dest), best_path.path)
50
- if best_path.path.empty? || best_path.distance.nil? || best_path.distance < 0
51
- raise NoPathExistsError
52
- end
53
- best_path
43
+ @edges[source] ||= []
44
+ @edges[source] << [dest, distance]
54
45
  end
55
46
 
56
- private
57
-
58
- def node(obj)
59
- @nodes[obj] ||= @nodes.size # Auto-increment id
47
+ def connections(source, &block)
48
+ @edges[source]&.each(&block)
49
+ nil
60
50
  end
61
51
 
62
52
  end
@@ -0,0 +1,68 @@
1
+ module DijkstraFast
2
+ ##
3
+ # Do not use this class. For internal purposes only.
4
+ ##
5
+ class Native
6
+
7
+ private
8
+
9
+ def initialize(delegate)
10
+ @delegate = delegate
11
+ @ids = {}
12
+ @nodes = {}
13
+ end
14
+
15
+ def connections(source_id)
16
+ @delegate.connections(node(source_id)) do |dest, distance = 1|
17
+ yield node_id(dest), distance
18
+ end
19
+ end
20
+
21
+ def shortest_path(source, dest, progress: false)
22
+ if !progress
23
+ progress = nil
24
+ elsif !progress.is_a?(Proc)
25
+ progress_bar = create_progress_bar(progress)
26
+ progress = lambda do |completed, total|
27
+ progress_bar.total = total
28
+ progress_bar.progress = completed
29
+ end
30
+ end
31
+
32
+ distance, path = _shortest_path(node_id(source), node_id(dest), progress)
33
+ [distance, @ids.invert.values_at(*path)]
34
+ ensure
35
+ progress_bar&.clear
36
+ end
37
+
38
+ def node_id(node)
39
+ id = @ids[node]
40
+ if id.nil?
41
+ id = @ids[node] = @ids.size + 1 # Auto-incrementing id (starting at 1 to leave 0 = nil)
42
+ @nodes[id] = node
43
+ end
44
+ id
45
+ end
46
+
47
+ def node(id)
48
+ @nodes.fetch(id)
49
+ end
50
+
51
+ def create_progress_bar(config)
52
+ require 'progressbar' unless defined?(ProgressBar)
53
+ return ProgressBar.create(config) if config.is_a?(Hash)
54
+
55
+ format = config.is_a?(String) ? config : "%a %b\u{15E7}%i %p%% %t"
56
+ ProgressBar.create(
57
+ format: format,
58
+ progress_mark: ' ',
59
+ remainder_mark: "\u{FF65}",
60
+ total: 100,
61
+ autofinish: false,
62
+ )
63
+ rescue LoadError
64
+ raise LoadError, 'The default implementation of progress reporting requires the progressbar gem'
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,96 @@
1
+ module DijkstraFast
2
+ ##
3
+ # Interface to allow arbitrary classes to calculate the shortest path between
4
+ # two "items" using a native implementation of Dijkstra's algorithm.
5
+ #
6
+ # @example
7
+ #
8
+ # class GraphOne
9
+ # include DijkstraFast::ShortestPath
10
+ #
11
+ # def connections(source)
12
+ # source.find_next do |dest, distance|
13
+ # yield dest, distance
14
+ # end
15
+ # end
16
+ # end
17
+ #
18
+ # distance, path = GraphOne.new.shortest_path(source, dest)
19
+ #
20
+ # @example
21
+ #
22
+ # class GraphTwo
23
+ # include DijkstraFast::ShortestPath
24
+ #
25
+ # def initialize
26
+ # # All edges have distance 1
27
+ # @edges = { 1 => [2, 3], 2 => [3] }
28
+ # end
29
+ #
30
+ # def connections(source, &block)
31
+ # @edges.fetch(source, []).each(&block)
32
+ # end
33
+ # end
34
+ #
35
+ # distance = GraphTwo.new.shortest_distance(source, dest)
36
+ #
37
+ # @example
38
+ #
39
+ # class GraphThree
40
+ # include DijkstraFast::ShortestPath
41
+ #
42
+ # def connections(source)
43
+ # case source
44
+ # when 'A'
45
+ # yield 'B', 3
46
+ # yield 'C' # Default distance 1
47
+ # when 'B'
48
+ # yield 'C', 10
49
+ # end
50
+ # end
51
+ # end
52
+ #
53
+ # distance, path = GraphThree.new.shortest_path(source, dest)
54
+ #
55
+ # @see README
56
+ # @see https://en.wikipedia.org/wiki/Dijkstra's_algorithm
57
+ ##
58
+ module ShortestPath
59
+
60
+ # Returns the edges originating at source
61
+ # @param source [Object] Any Ruby object that represents the source item
62
+ # @yield [Object, int] A connection to destination object with given distance
63
+ # @return [nil]
64
+ def connections(source)
65
+ # Does nothing by default but should be implemented by class
66
+ end
67
+
68
+ # Finds the shortest path between items, returning both the path as well as
69
+ # the total distance travelled.
70
+ # @param source [Object] Any Ruby object that represents the source item
71
+ # @param dest [Object] Any Ruby object that represents the destination item
72
+ # @param progress [Boolean|String|Proc] If falsey (default), no progress will
73
+ # be displayed. If a Proc is given, it will be yielded progress
74
+ # (completed / total) as progress is made. If otherwise truthy the
75
+ # ruby-progressbar gem will be required and displayed; if passed a
76
+ # String it will be used as the progress bar's format.
77
+ # @return [Array<int, Array>]
78
+ def shortest_path(source, dest, progress: false)
79
+ Native.new(self).send(:shortest_path, source, dest, progress: progress)
80
+ end
81
+
82
+ # Finds the shortest distance between items
83
+ # @param source [Object] Any Ruby object that represents the source item
84
+ # @param dest [Object] Any Ruby object that represents the destination item
85
+ # @param progress [Boolean|String|Proc] If falsey (default), no progress will
86
+ # be displayed. If a Proc is given, it will be yielded progress
87
+ # (completed / total) as progress is made. If otherwise truthy the
88
+ # ruby-progressbar gem will be required and displayed; if passed a
89
+ # String it will be used as the progress bar's format.
90
+ # @return [int]
91
+ def shortest_distance(source, dest, progress: false)
92
+ shortest_path(source, dest, progress: progress).first
93
+ end
94
+
95
+ end
96
+ end
@@ -1,6 +1,6 @@
1
1
  module DijkstraFast
2
2
 
3
3
  # Current gem version
4
- VERSION = '1.4.2'
4
+ VERSION = '1.5.2'
5
5
 
6
6
  end
data/lib/dijkstra_fast.rb CHANGED
@@ -1,22 +1,92 @@
1
1
  ##
2
- # Provides native implementation of Dijkstra's algorithm for finding the shortest
3
- # path between two vertices in a large, sparse graph.
2
+ # When graph nodes "know" which nodes they are connected to, one of the two
3
+ # class methods on this module can be be used directly to calculate the shortest
4
+ # distance between nodes. Node objects must implement a method (by default
5
+ # <code>connections</code>) which yields all connected nodes and (optionally) the
6
+ # distance to that connected node. If the yield only supplies the connected
7
+ # node, a defualt distance of <code>1</code> is used.
4
8
  #
5
- # Underlying algorithm is implemented in C using a priority queue. Edges are
6
- # represented using linked lists rather than an adjacency matrix to reduce memory
7
- # footprint when operating on very large graphs where the average number of edges
8
- # between nodes is relatively small (e.g. < 1/10 the number of nodes). See
9
+ # It is important to ensure that <code>hash</code> and <code>eql?</code> are properly implemented so
10
+ # that two objects that are logically the same are treatest thusly.
9
11
  #
10
- # @see README
11
- # @see https://en.wikipedia.org/wiki/Dijkstra's_algorithm
12
+ # @example
13
+ #
14
+ # class SomethingWithConnections
15
+ # def find_next
16
+ # yield SomethingWithConnections.new('C'), 2
17
+ # yield SomethingWithConnections.new('D'), 4
18
+ # end
19
+ #
20
+ # def hash
21
+ # # implement me
22
+ # end
23
+ #
24
+ # def eql?(other)
25
+ # # implement me
26
+ # end
27
+ # end
28
+ #
29
+ # a = SomethingWithConnections.new('A')
30
+ # b = SomethingWithConnections.new('B')
31
+ # distance, path = DijkstraFast.shortest_path(a, b, connections: :find_next)
32
+ #
33
+ # @example
34
+ #
35
+ # class SomethingElseWithConnections
36
+ # def connections
37
+ # yield # implement me
38
+ # yield # implement me
39
+ # end
40
+ # end
41
+ #
42
+ # a = SomethingElseWithConnections.new
43
+ # b = SomethingElseWithConnections.new
44
+ # distance = DijkstraFast.shortest_distance(a, b)
12
45
  ##
13
46
  module DijkstraFast
14
47
 
15
- autoload :BestPath, 'dijkstra_fast/best_path'
16
48
  autoload :Graph, 'dijkstra_fast/graph'
49
+ autoload :Native, 'dijkstra_fast/native'
17
50
  autoload :NoPathExistsError, 'dijkstra_fast/no_path_exists_error'
51
+ autoload :PriorityQueue, 'dijkstra_fast/priority_queue'
52
+ autoload :ShortestPath, 'dijkstra_fast/shortest_path'
18
53
  autoload :VERSION, 'dijkstra_fast/version'
19
54
 
55
+ # Finds the shortest path between items, returning both the path as well as
56
+ # the total distance travelled.
57
+ # @param source [Object] Any Ruby object that represents the source item
58
+ # @param dest [Object] Any Ruby object that represents the destination item
59
+ # @param progress [Boolean|String|Proc] If falsey (default), no progress will
60
+ # be displayed. If a Proc is given, it will be yielded progress
61
+ # (completed / total) as progress is made. If otherwise truthy the
62
+ # ruby-progressbar gem will be required and displayed; if passed a
63
+ # String it will be used as the progress bar's format.
64
+ # @param connections [Symbol|String] The method to call on each item to
65
+ # obtain adjacent items in the graph. Defaults to 'connections'
66
+ # @return [Array<int, Array>]
67
+ def self.shortest_path(source, dest, connections: 'connections', progress: false)
68
+ clazz = Class.new { include DijkstraFast::ShortestPath }
69
+ clazz.define_method(:connections) do |source, &block|
70
+ source.send(connections, &block)
71
+ end
72
+ clazz.new.shortest_path(source, dest, progress: progress)
73
+ end
74
+
75
+ # Finds the shortest distance between items
76
+ # @param source [Object] Any Ruby object that represents the source item
77
+ # @param dest [Object] Any Ruby object that represents the destination item
78
+ # @param progress [Boolean|String|Proc] If falsey (default), no progress will
79
+ # be displayed. If a Proc is given, it will be yielded progress
80
+ # (completed / total) as progress is made. If otherwise truthy the
81
+ # ruby-progressbar gem will be required and displayed; if passed a
82
+ # String it will be used as the progress bar's format.
83
+ # @param connections [Symbol|String] The method to call on each item to
84
+ # obtain adjacent items in the graph.
85
+ # @return [int]
86
+ def self.shortest_distance(source, dest, connections: 'connections', progress: false)
87
+ shortest_path(source, dest, connections: connections, progress: progress).first
88
+ end
89
+
20
90
  end
21
91
 
22
92
  require 'dijkstra_fast/dijkstra_fast'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dijkstra_fast
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David McCullars
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-23 00:00:00.000000000 Z
11
+ date: 2022-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: github-markup
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: redcarpet
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rspec
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -157,6 +185,7 @@ files:
157
185
  - ".rubocop.yml"
158
186
  - ".ruby-version"
159
187
  - ".travis.yml"
188
+ - ".yardopts"
160
189
  - CODE_OF_CONDUCT.md
161
190
  - Gemfile
162
191
  - LICENSE
@@ -164,20 +193,26 @@ files:
164
193
  - Rakefile
165
194
  - dijkstra_fast.gemspec
166
195
  - ext/dijkstra_fast/dijkstra_fast.c
167
- - ext/dijkstra_fast/dijkstra_graph.c
168
- - ext/dijkstra_fast/dijkstra_graph.h
196
+ - ext/dijkstra_fast/errors.c
197
+ - ext/dijkstra_fast/errors.h
198
+ - ext/dijkstra_fast/expand_capacity.h
169
199
  - ext/dijkstra_fast/extconf.rb
170
- - ext/dijkstra_fast/prioritized_item_list.c
171
- - ext/dijkstra_fast/prioritized_item_list.h
200
+ - ext/dijkstra_fast/native.c
201
+ - ext/dijkstra_fast/native.h
202
+ - ext/dijkstra_fast/native_shortest_path.c
203
+ - ext/dijkstra_fast/priority_queue.c
204
+ - ext/dijkstra_fast/priority_queue.h
172
205
  - lib/dijkstra_fast.rb
173
- - lib/dijkstra_fast/best_path.rb
174
206
  - lib/dijkstra_fast/graph.rb
207
+ - lib/dijkstra_fast/native.rb
175
208
  - lib/dijkstra_fast/no_path_exists_error.rb
209
+ - lib/dijkstra_fast/shortest_path.rb
176
210
  - lib/dijkstra_fast/version.rb
177
211
  homepage: https://github.com/david-mccullars/dijkstra_fast
178
212
  licenses:
179
213
  - MIT
180
- metadata: {}
214
+ metadata:
215
+ rubygems_mfa_required: 'true'
181
216
  post_install_message:
182
217
  rdoc_options: []
183
218
  require_paths:
@@ -186,7 +221,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
221
  requirements:
187
222
  - - ">="
188
223
  - !ruby/object:Gem::Version
189
- version: '0'
224
+ version: 3.0.0
190
225
  required_rubygems_version: !ruby/object:Gem::Requirement
191
226
  requirements:
192
227
  - - ">="
@@ -1,234 +0,0 @@
1
- #include <ruby.h>
2
- #include <dijkstra_graph.h>
3
- #include <prioritized_item_list.h>
4
-
5
- const size_t VERTEX_LIST_SIZE = sizeof(VertexListStruct);
6
- const size_t EDGE_LIST_SIZE = sizeof(EdgeListStruct);
7
- const size_t VERTEX_SIZE = sizeof(VertexStruct);
8
- const size_t EDGE_SIZE = sizeof(EdgeStruct);
9
- const size_t GRAPH_SIZE = sizeof(GraphStruct);
10
-
11
- static const rb_data_type_t graph_typed_data = {
12
- "Dijkstra/Graph",
13
- { 0, free_graph, },
14
- 0, 0,
15
- RUBY_TYPED_FREE_IMMEDIATELY,
16
- };
17
-
18
- //////////////////////////////////////////////////////////////////////////////////////
19
-
20
- void Init_dijkstra_graph() {
21
- VALUE DijkstraFastModule, GraphClass;
22
-
23
- DijkstraFastModule = rb_const_get(rb_cObject, rb_intern("DijkstraFast"));
24
- GraphClass = rb_const_get(DijkstraFastModule, rb_intern("Graph"));
25
-
26
- rb_define_alloc_func(GraphClass, dijkstra_graph_allocate);
27
- rb_define_private_method(GraphClass, "_add_edge", dijkstra_graph_add_edge, 3);
28
- rb_define_private_method(GraphClass, "_shortest_path", dijkstra_graph_shortest_path, 3);
29
- }
30
-
31
- VALUE dijkstra_graph_allocate(VALUE self) {
32
- Graph g = malloc(GRAPH_SIZE);
33
-
34
- // Grab a reference to the hash type used by a generic Ruby {}
35
- // which accepts any key and any value. We'll need this type to create
36
- // a st_table in which to put arbitrary VALUE keys. This hash type
37
- // should be a static constant and thus should be safe to utilize without
38
- // fear of garbage collection.
39
- const struct st_hash_type *objhash = rb_hash_tbl(rb_hash_new(), "dijkstra.c", 1)->type;
40
-
41
- g->vertex_count = 0;
42
- g->vertices = NULL;
43
- g->vertex_lookup = st_init_table_with_size(objhash, 0);
44
-
45
- return TypedData_Wrap_Struct(self, &graph_typed_data, g);
46
- }
47
-
48
- VALUE dijkstra_graph_add_edge(VALUE self, VALUE source_label, VALUE dest_label, VALUE distance) {
49
- Graph g;
50
-
51
- TypedData_Get_Struct(self, GraphStruct, &graph_typed_data, g);
52
- add_edge_with_labels(g, source_label, dest_label, NUM2INT(distance));
53
- return Qnil;
54
- }
55
-
56
- VALUE dijkstra_graph_shortest_path(VALUE self, VALUE source_label, VALUE dest_label, VALUE best_path) {
57
- Graph g;
58
- Vertex source, dest;
59
-
60
- TypedData_Get_Struct(self, GraphStruct, &graph_typed_data, g);
61
- source = lookup_vertex(g, source_label, false);
62
- dest = lookup_vertex(g, dest_label, false);
63
-
64
- if (source == NULL || dest == NULL) {
65
- return Qnil;
66
- } else {
67
- return INT2NUM(shortest_path(g, source, dest, best_path));
68
- }
69
- }
70
-
71
- //////////////////////////////////////////////////////////////////////////////////////
72
-
73
- void free_graph(void *data) {
74
- Graph g = (Graph)data;
75
-
76
- struct EdgeListStruct **vertices;
77
-
78
- free_vertex_list(g->vertices, free_vertex);
79
- free(g->vertex_lookup);
80
- free(g);
81
- }
82
-
83
- void free_vertex(Vertex n) {
84
- free_edge_list(n->edges, free_edge);
85
- free(n);
86
- }
87
-
88
- void free_vertex_list(VertexList vertices, void (*free_item)(Vertex)) {
89
- VertexList tmp;
90
- while (vertices != NULL) {
91
- tmp = vertices;
92
- vertices = vertices->next;
93
- if (free_item) {
94
- free_item(tmp->vertex);
95
- }
96
- free(tmp);
97
- }
98
- }
99
-
100
- void free_edge(Edge e) {
101
- // Assume source and destination vertices were allocated elsewhere and will be free'd elsewhere
102
- free(e);
103
- }
104
-
105
- void free_edge_list(EdgeList edges, void (*free_item)(Edge)) {
106
- EdgeList tmp;
107
- while (edges != NULL) {
108
- tmp = edges;
109
- edges = edges->next;
110
- if (free_item) {
111
- free_item(tmp->edge);
112
- }
113
- free(tmp);
114
- }
115
- }
116
-
117
- //////////////////////////////////////////////////////////////////////////////////////
118
-
119
- Vertex add_vertex(Graph g, VALUE label) {
120
- VertexList tmp = malloc(VERTEX_LIST_SIZE);
121
-
122
- tmp->vertex = malloc(VERTEX_SIZE);
123
- tmp->vertex->id = g->vertices != NULL ? g->vertices->vertex->id + 1 : 0; // Auto-incrementing id
124
- tmp->vertex->label = label;
125
- tmp->vertex->edges = NULL;
126
-
127
- tmp->next = g->vertices;
128
- g->vertices = tmp;
129
- g->vertex_count += 1;
130
-
131
- return tmp->vertex;
132
- }
133
-
134
- VertexList add_vertex_to_list(VertexList list, VALUE label) {
135
- VertexList tmp = malloc(VERTEX_LIST_SIZE);
136
-
137
- tmp->vertex = malloc(VERTEX_SIZE);
138
- tmp->vertex->label = label;
139
- tmp->vertex->edges = NULL;
140
-
141
- tmp->next = list;
142
- return tmp;
143
- }
144
-
145
- Edge add_edge(Vertex source, Vertex dest, int distance) {
146
- EdgeList tmp = malloc(EDGE_LIST_SIZE);
147
-
148
- tmp->edge = malloc(EDGE_SIZE);
149
- tmp->edge->source = source;
150
- tmp->edge->dest = dest;
151
- tmp->edge->distance = distance;
152
-
153
- tmp->next = source->edges;
154
- source->edges = tmp;
155
-
156
- return tmp->edge;
157
- }
158
-
159
- Edge add_edge_with_labels(Graph g, VALUE source_label, VALUE dest_label, int distance) {
160
- Vertex source, dest;
161
-
162
- source = lookup_vertex(g, source_label, true);
163
- dest = lookup_vertex(g, dest_label, true);
164
-
165
- return add_edge(source, dest, distance);
166
- }
167
-
168
- Vertex lookup_vertex(Graph g, VALUE label, bool create_if_missing) {
169
- Vertex n = NULL;
170
-
171
- if (!st_lookup(g->vertex_lookup, (st_data_t)label, (st_data_t *)&n)) {
172
- if (!create_if_missing) return NULL;
173
- n = add_vertex(g, label);
174
- st_add_direct(g->vertex_lookup, (st_data_t)label, (st_data_t)n);
175
- }
176
- return n;
177
- }
178
-
179
- //////////////////////////////////////////////////////////////////////////////////////
180
-
181
- int shortest_path(Graph g, Vertex source, Vertex dest, VALUE best_path) {
182
- Vertex *items, *prevs;
183
- PrioritizedItemList list;
184
-
185
- int d, du, dv;
186
- Vertex u, v;
187
- VertexList vl;
188
- EdgeList el;
189
- bool reached = source == dest;
190
-
191
- items = malloc(g->vertex_count * sizeof(Vertex));
192
- prevs = malloc(g->vertex_count * sizeof(Vertex));
193
- list = make_prioritized_item_list(g->vertex_count);
194
-
195
- for (vl = g->vertices; vl != NULL; vl = vl->next) {
196
- v = vl->vertex;
197
- items[v->id] = v;
198
- prevs[v->id] = NULL;
199
- }
200
-
201
- update_prioritized_item(list, source->id, 0);
202
-
203
- while (!empty_prioritized_item_list(list)) {
204
- u = items[next_prioritized_item(list)];
205
- du = get_priority(list, u->id);
206
- for (el = u->edges; el != NULL; el = el->next) {
207
- v = el->edge->dest;
208
- dv = get_priority(list, v->id);
209
- d = du + el->edge->distance;
210
- if (d < 0) d = INT_MAX; // Wrapped around
211
-
212
- if (in_prioritized_item_list(list, v->id) && d < dv) {
213
- update_prioritized_item(list, v->id, d);
214
- prevs[v->id] = u;
215
- reached = reached || v == dest;
216
- }
217
- }
218
- }
219
-
220
- if (reached) {
221
- for (v = dest; v != NULL; v = prevs[v->id]) {
222
- rb_ary_unshift(best_path, v->label);
223
- }
224
- d = get_priority(list, dest->id);
225
- } else {
226
- d = -1;
227
- }
228
-
229
- free(items);
230
- free(prevs);
231
- free_prioritized_item_list(list);
232
-
233
- return d;
234
- }