dijkstra_fast 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '0806b283afa40238d914c51d06c587a4dc053d65431bb68c55b6a06a827bb245'
4
+ data.tar.gz: c070c8d2f5bfb38b3fe25469190ef460ca1581a3c670b1715cb3696b6e46373b
5
+ SHA512:
6
+ metadata.gz: 04640eac7496a7fd98dae710d4582f27397b86f4782e9c6fec3eb4a4ef4d46aff809c33a7295dee419c56f09a276214937b09beb1a03220bcbcf3c65d977e2d6
7
+ data.tar.gz: ee26aad2a4a9ab681754e4b8682f8b465e94bc36797da88f3d2ef62de260f4e69e9f2c80dd6856962f3e80a88f3e31cc3e871d9ac9d5d0146a6cfb10906856c7
data/.codeclimate.yml ADDED
@@ -0,0 +1,24 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ checks:
9
+ Similar code:
10
+ enabled: false
11
+ fixme:
12
+ enabled: true
13
+ rubocop:
14
+ enabled: true
15
+ exclude_fingerprints:
16
+ - 4218049e28199ed950d3cd721df86dce
17
+ - c8179d0de3a9df18a2c45750d3f8647e
18
+ - 03f6eee11d86507da564695007106721
19
+ channel: rubocop-1-23-0
20
+ ratings:
21
+ paths:
22
+ - "**.rb"
23
+ exclude_paths:
24
+ - spec/
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.rake_tasks
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /html/
8
+ /doc/
9
+ /pkg/
10
+ /spec/reports/
11
+ /tmp/
12
+
13
+ *.bundle
14
+ *.so
15
+ extconf.rb
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,195 @@
1
+ AllCops:
2
+ Exclude:
3
+ - dijkstra.gemspec
4
+ - Rakefile
5
+ - ext/**/*
6
+ - tmp/**/*
7
+ Gemspec/DateAssignment:
8
+ Enabled: true
9
+ Gemspec/RequireMFA:
10
+ Enabled: true
11
+ Layout/EmptyLinesAroundAttributeAccessor:
12
+ Enabled: true
13
+ Layout/EmptyLinesAroundClassBody:
14
+ EnforcedStyle: empty_lines_except_namespace
15
+ Layout/EmptyLinesAroundModuleBody:
16
+ EnforcedStyle: empty_lines_except_namespace
17
+ Layout/ExtraSpacing:
18
+ Enabled: false
19
+ Layout/HashAlignment:
20
+ EnforcedHashRocketStyle: table
21
+ EnforcedColonStyle: table
22
+ Layout/LineEndStringConcatenationIndentation:
23
+ Enabled: true
24
+ Layout/LineLength:
25
+ Max: 120
26
+ Enabled: false
27
+ Layout/SpaceAroundMethodCallOperator:
28
+ Enabled: true
29
+ Layout/SpaceBeforeBrackets:
30
+ Enabled: true
31
+ Lint/AmbiguousAssignment:
32
+ Enabled: true
33
+ Lint/AmbiguousOperatorPrecedence:
34
+ Enabled: true
35
+ Lint/AmbiguousRange:
36
+ Enabled: true
37
+ Lint/DeprecatedConstants:
38
+ Enabled: true
39
+ Lint/DeprecatedOpenSSLConstant:
40
+ Enabled: true
41
+ Lint/DuplicateBranch:
42
+ Enabled: true
43
+ Lint/DuplicateRegexpCharacterClassElement:
44
+ Enabled: true
45
+ Lint/EmptyBlock:
46
+ Enabled: true
47
+ Lint/EmptyClass:
48
+ Enabled: true
49
+ Lint/EmptyInPattern:
50
+ Enabled: true
51
+ Lint/IncompatibleIoSelectWithFiberScheduler:
52
+ Enabled: true
53
+ Lint/LambdaWithoutLiteralBlock:
54
+ Enabled: true
55
+ Lint/MixedRegexpCaptureTypes:
56
+ Enabled: true
57
+ Lint/NoReturnInBeginEndBlocks:
58
+ Enabled: true
59
+ Lint/NumberedParameterAssignment:
60
+ Enabled: true
61
+ Lint/OrAssignmentToConstant:
62
+ Enabled: true
63
+ Lint/RaiseException:
64
+ Enabled: true
65
+ Lint/RedundantDirGlobSort:
66
+ Enabled: true
67
+ Lint/RequireRelativeSelfPath:
68
+ Enabled: true
69
+ Lint/StructNewOverride:
70
+ Enabled: true
71
+ Lint/SymbolConversion:
72
+ Enabled: true
73
+ Lint/ToEnumArguments:
74
+ Enabled: true
75
+ Lint/TripleQuotes:
76
+ Enabled: true
77
+ Lint/UnexpectedBlockArity:
78
+ Enabled: true
79
+ Lint/UnmodifiedReduceAccumulator:
80
+ Enabled: true
81
+ Lint/UselessRuby2Keywords:
82
+ Enabled: true
83
+ Metrics/AbcSize:
84
+ Max: 50
85
+ Enabled: false
86
+ Metrics/BlockLength:
87
+ Max: 50
88
+ Enabled: false
89
+ Metrics/ClassLength:
90
+ Max: 50
91
+ Enabled: false
92
+ Metrics/CyclomaticComplexity:
93
+ Max: 30
94
+ Enabled: false
95
+ Metrics/MethodLength:
96
+ Max: 20
97
+ Enabled: false
98
+ Metrics/ModuleLength:
99
+ Max: 1000
100
+ Enabled: false
101
+ Metrics/PerceivedComplexity:
102
+ Max: 30
103
+ Enabled: false
104
+ Security/IoMethods:
105
+ Enabled: true
106
+ Security/MarshalLoad:
107
+ Enabled: false
108
+ Style/AndOr:
109
+ Enabled: false
110
+ Style/ArgumentsForwarding:
111
+ Enabled: true
112
+ Style/CaseEquality:
113
+ Enabled: false
114
+ Style/CollectionCompact:
115
+ Enabled: true
116
+ Style/DocumentDynamicEvalDefinition:
117
+ Enabled: true
118
+ Style/Documentation:
119
+ Enabled: false
120
+ Style/DoubleNegation:
121
+ Enabled: false
122
+ Style/EndlessMethod:
123
+ Enabled: true
124
+ Style/ExponentialNotation:
125
+ Enabled: true
126
+ Style/FrozenStringLiteralComment:
127
+ Enabled: false
128
+ Style/GuardClause:
129
+ Enabled: false
130
+ Style/HashConversion:
131
+ Enabled: true
132
+ Style/HashEachMethods:
133
+ Enabled: true
134
+ Style/HashExcept:
135
+ Enabled: true
136
+ Style/HashSyntax:
137
+ Enabled: true
138
+ Style/HashTransformKeys:
139
+ Enabled: true
140
+ Style/HashTransformValues:
141
+ Enabled: true
142
+ Style/IfUnlessModifier:
143
+ Enabled: false
144
+ Style/IfWithBooleanLiteralBranches:
145
+ Enabled: true
146
+ Style/InPatternThen:
147
+ Enabled: true
148
+ Style/MultilineBlockChain:
149
+ Enabled: false
150
+ Style/MultilineIfModifier:
151
+ Enabled: false
152
+ Style/MultilineInPatternThen:
153
+ Enabled: true
154
+ Style/MutableConstant:
155
+ Enabled: false
156
+ Style/NegatedIfElseCondition:
157
+ Enabled: true
158
+ Style/NilLambda:
159
+ Enabled: true
160
+ Style/NumberedParameters:
161
+ Enabled: true
162
+ Style/NumberedParametersLimit:
163
+ Enabled: true
164
+ Style/OpenStructUse:
165
+ Enabled: true
166
+ Style/QuotedSymbols:
167
+ Enabled: true
168
+ Style/RedundantArgument:
169
+ Enabled: true
170
+ Style/RedundantRegexpCharacterClass:
171
+ Enabled: true
172
+ Style/RedundantRegexpEscape:
173
+ Enabled: true
174
+ Style/RedundantSelfAssignmentBranch:
175
+ Enabled: true
176
+ Style/RescueModifier:
177
+ Enabled: false
178
+ Style/RescueStandardError:
179
+ Enabled: false
180
+ Style/SelectByRegexp:
181
+ Enabled: true
182
+ Style/SlicingWithRange:
183
+ Enabled: true
184
+ Style/StringChars:
185
+ Enabled: true
186
+ Style/SwapValues:
187
+ Enabled: true
188
+ Style/TrailingCommaInArguments:
189
+ EnforcedStyleForMultiline: comma
190
+ Style/TrailingCommaInArrayLiteral:
191
+ EnforcedStyleForMultiline: consistent_comma
192
+ Style/TrailingCommaInHashLiteral:
193
+ EnforcedStyleForMultiline: consistent_comma
194
+ Style/ZeroLengthPredicate:
195
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.3
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ env:
2
+ global:
3
+ - CC_TEST_REPORTER_ID=b5370328873f97034f05a0c49b63b7d13b6eeaed129f1bdf17509f183cd6a2f7
4
+ language: ruby
5
+ rvm:
6
+ - 3.0.3
7
+ before_install: gem install bundler -v 2.2.32
8
+ before_script:
9
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
10
+ - chmod +x ./cc-test-reporter
11
+ - ./cc-test-reporter before-build
12
+ - bundle exec rake compile
13
+ script:
14
+ - bundle exec rspec
15
+ after_script:
16
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at david@bloomfire.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 David McCullars
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Dijkstra (Fast!)
2
+
3
+ * README: https://github.com/david-mccullars/dijkstra_fast
4
+ * Documentation: http://www.rubydoc.info/github/david-mccullars/dijkstra_fast
5
+ * Bug Reports: https://github.com/david-mccullars/dijkstra_fast/issues
6
+
7
+
8
+ ## Status
9
+
10
+ [![Gem Version](https://badge.fury.io/rb/dijkstra_fast.svg)](https://badge.fury.io/rb/dijkstra_fast)
11
+ [![Travis Build Status](https://travis-ci.org/david-mccullars/dijkstra_fast.svg?branch=master)](https://travis-ci.org/david-mccullars/dijkstra_fast)
12
+ [![Code Climate](https://codeclimate.com/github/david-mccullars/dijkstra_fast/badges/gpa.svg)](https://codeclimate.com/github/david-mccullars/dijkstra_fast)
13
+ [![Test Coverage](https://codeclimate.com/github/david-mccullars/dijkstra_fast/badges/coverage.svg)](https://codeclimate.com/github/david-mccullars/dijkstra_fast/coverage)
14
+
15
+
16
+ ## Description
17
+
18
+ [Dijkstra](https://en.wikipedia.org/wiki/Dijkstra's_algorithm) is a commonly
19
+ used algorithm for finding the shortest path through a graph or network.
20
+
21
+
22
+ ## Features
23
+
24
+ * Native implementation of Dijkstra's algorithm intended for use on large,
25
+ sparse graphs for which an array of arrays is inefficient.
26
+
27
+
28
+ ## Installation
29
+
30
+ ```
31
+ gem install dijkstra_fast
32
+ ```
33
+
34
+ ## Requirements
35
+
36
+ * Ruby 3.0 or higher
37
+
38
+ ## Usage
39
+
40
+ **Dijkstra**
41
+
42
+ ```ruby
43
+ require 'dijkstra_fast'
44
+
45
+ graph = DijkstraFast::Graph.new
46
+ graph.add("A", "B", distance: 5)
47
+ graph.add("A", "C", distance: 8)
48
+ graph.add("B", "C", distance: 2)
49
+ best_path = graph.shortest_path("A", "C")
50
+ best_path.path
51
+
52
+ => ["A", "B", "C"]
53
+
54
+ best_path.distance
55
+
56
+ => 7
57
+ ```
58
+
59
+
60
+ ## License
61
+
62
+ MIT. See the `LICENSE` file.
63
+
64
+
65
+ ## References
66
+
67
+ > Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2001). "Section 24.3: Dijkstra's algorithm". Introduction to Algorithms (Second ed.). MIT Press and McGraw–Hill. pp. 595–601. ISBN 0-262-03293-7.
68
+
69
+ > Knuth, D.E. (1977). "A Generalization of Dijkstra's Algorithm". Information Processing Letters. 6 (1): 1–5. doi:10.1016/0020-0190(77)90002-3.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/extensiontask"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ require 'rdoc/task'
10
+ RDoc::Task.new do |rdoc|
11
+ rdoc.main = "README.md"
12
+ rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
13
+ end
14
+
15
+ Rake::ExtensionTask.new('dijkstra_fast') do |ext|
16
+ ext.lib_dir = 'lib/dijkstra_fast'
17
+ end
@@ -0,0 +1,39 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'dijkstra_fast/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'dijkstra_fast'
7
+ spec.version = DijkstraFast::VERSION
8
+ spec.authors = ['David McCullars']
9
+ spec.email = ['david.mccullars@gmail.com']
10
+
11
+ spec.summary = '(Native) implementation of Dijkstra algorithm for large, sparse graphs'
12
+ spec.description = <<~DESCRIPTION
13
+ Native implementation of Dijkstra algorithm for finding the shortest path
14
+ between two vertices in a large, sparse graphs. Underlying algorithm is
15
+ implemented in C using a priority queue. Edges are represented using linked
16
+ lists rather than an adjacency matrix to reduce memory footprint when operating
17
+ on very large graphs where the average number of edges between nodes is
18
+ relatively small (e.g. < 1/10 the number of nodes). See
19
+ https://en.wikipedia.org/wiki/Dijkstra's_algorithm for additional information.
20
+ DESCRIPTION
21
+ spec.homepage = 'https://github.com/david-mccullars/dijkstra_fast'
22
+ spec.license = 'MIT'
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.extensions = ['ext/dijkstra_fast/extconf.rb']
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_development_dependency 'bundler'
31
+ spec.add_development_dependency 'rake'
32
+ spec.add_development_dependency 'rake-compiler'
33
+ spec.add_development_dependency 'rspec'
34
+ spec.add_development_dependency 'rubocop'
35
+ spec.add_development_dependency 'rubocop-rake'
36
+ spec.add_development_dependency 'rubocop-rspec'
37
+ spec.add_development_dependency 'simplecov'
38
+ spec.add_development_dependency 'yard'
39
+ end
@@ -0,0 +1,5 @@
1
+ #include <dijkstra_graph.h>
2
+
3
+ void Init_dijkstra_fast() {
4
+ Init_dijkstra_graph();
5
+ }
@@ -0,0 +1,234 @@
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
+ }
@@ -0,0 +1,83 @@
1
+ #ifndef DIJKSTRA_GRAPH_H
2
+ #define DIJKSTRA_GRAPH_H
3
+
4
+ #include <ruby.h>
5
+
6
+ struct VertexListStruct;
7
+ typedef struct VertexListStruct* VertexList;
8
+
9
+ typedef struct VertexListStruct {
10
+ struct VertexStruct *vertex;
11
+ struct VertexListStruct *next;
12
+ } VertexListStruct;
13
+
14
+ //////////////////////////////////////////////////////////////////////////////////////
15
+
16
+ struct EdgeListStruct;
17
+ typedef struct EdgeListStruct* EdgeList;
18
+
19
+ typedef struct EdgeListStruct {
20
+ struct EdgeStruct *edge;
21
+ struct EdgeListStruct *next;
22
+ } EdgeListStruct;
23
+
24
+ //////////////////////////////////////////////////////////////////////////////////////
25
+
26
+ struct VertexStruct;
27
+ typedef struct VertexStruct* Vertex;
28
+
29
+ typedef struct VertexStruct {
30
+ EdgeList edges;
31
+ int id;
32
+ VALUE label;
33
+ } VertexStruct;
34
+
35
+ //////////////////////////////////////////////////////////////////////////////////////
36
+
37
+ struct EdgeStruct;
38
+ typedef struct EdgeStruct* Edge;
39
+
40
+ typedef struct EdgeStruct {
41
+ Vertex source;
42
+ Vertex dest;
43
+ int distance;
44
+ } EdgeStruct;
45
+
46
+ //////////////////////////////////////////////////////////////////////////////////////
47
+
48
+ struct GraphStruct;
49
+ typedef struct GraphStruct* Graph;
50
+
51
+ typedef struct GraphStruct {
52
+ unsigned long vertex_count;
53
+ VertexList vertices;
54
+ st_table *vertex_lookup;
55
+ } GraphStruct;
56
+
57
+ //////////////////////////////////////////////////////////////////////////////////////
58
+
59
+ void free_graph(void *data);
60
+ void free_vertex(Vertex n);
61
+ void free_vertex_list(VertexList vertices, void (*free_item)(Vertex));
62
+ void free_edge(Edge e);
63
+ void free_edge_list(EdgeList edges, void (*free_item)(Edge));
64
+
65
+ //////////////////////////////////////////////////////////////////////////////////////
66
+
67
+ Vertex add_vertex(Graph g, VALUE label);
68
+ Edge add_edge(Vertex source, Vertex dest, int distance);
69
+ Edge add_edge_with_labels(Graph g, VALUE source_label, VALUE dest_label, int distance);
70
+ Vertex lookup_vertex(Graph g, VALUE label, bool create_if_missing);
71
+
72
+ //////////////////////////////////////////////////////////////////////////////////////
73
+
74
+ int shortest_path(Graph g, Vertex source, Vertex dest, VALUE best_path);
75
+
76
+ //////////////////////////////////////////////////////////////////////////////////////
77
+
78
+ void Init_dijkstra_graph();
79
+ VALUE dijkstra_graph_allocate(VALUE self);
80
+ VALUE dijkstra_graph_add_edge(VALUE self, VALUE source_label, VALUE dest_label, VALUE distance);
81
+ VALUE dijkstra_graph_shortest_path(VALUE self, VALUE source_label, VALUE dest_label, VALUE best_path);
82
+
83
+ #endif
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile('dijkstra_fast/dijkstra_fast')
@@ -0,0 +1,128 @@
1
+ #include <prioritized_item_list.h>
2
+
3
+ PrioritizedItemList make_prioritized_item_list(int capacity) {
4
+ int i;
5
+
6
+ PrioritizedItemList list = malloc(sizeof(PrioritizedItemListStruct));
7
+ list->priorities = malloc(capacity * sizeof(PrioritizedItem));
8
+ list->indices = malloc(capacity * sizeof(int));
9
+ list->capacity = capacity;
10
+ list->last = capacity - 1;
11
+ for (i = 0; i < capacity; i++) {
12
+ list->priorities[i] = malloc(sizeof(PrioritizedItemStruct));
13
+ list->priorities[i]->item = i;
14
+ list->priorities[i]->priority = INT_MAX;
15
+ list->indices[i] = i;
16
+ }
17
+ return list;
18
+ }
19
+
20
+ bool empty_prioritized_item_list(PrioritizedItemList list) {
21
+ return list->last < 0;
22
+ }
23
+
24
+ bool in_prioritized_item_list(PrioritizedItemList list, int item) {
25
+ return list->indices[item] <= list->last;
26
+ }
27
+
28
+ void swap_prioritized_items(PrioritizedItemList list, int i, int j) {
29
+ PrioritizedItem tmp = list->priorities[i];
30
+ list->priorities[i] = list->priorities[j];
31
+ list->priorities[j] = tmp;
32
+ list->indices[list->priorities[i]->item] = i;
33
+ list->indices[list->priorities[j]->item] = j;
34
+ }
35
+
36
+ void reprioritize_right(PrioritizedItemList list, int i) {
37
+ int orig_i = i;
38
+ int wi, wj_left, wj_right;
39
+ int j_left, j_right;
40
+ wi = list->priorities[i]->priority;
41
+
42
+ while (true) {
43
+ j_left = (i << 1) + 1;
44
+ j_right = j_left + 1;
45
+
46
+ wj_left = j_left <= list->last ? list->priorities[j_left]->priority : INT_MAX;
47
+ wj_right = j_right <= list->last ? list->priorities[j_right]->priority : INT_MAX;
48
+
49
+ if (wj_right < wi && wj_right < wj_left) {
50
+ swap_prioritized_items(list, i, j_right);
51
+ i = j_right;
52
+
53
+ } else if (wj_left < wi) {
54
+ swap_prioritized_items(list, i, j_left);
55
+ i = j_left;
56
+
57
+ } else {
58
+ return;
59
+ }
60
+ }
61
+ }
62
+
63
+ void reprioritize_left(PrioritizedItemList list, int i) {
64
+ int wi, wj;
65
+ int j;
66
+ wi = list->priorities[i]->priority;
67
+
68
+ while (i > 0) {
69
+ j = (i - 1) >> 1;
70
+ wj = list->priorities[j]->priority;
71
+
72
+ if (wj > wi) {
73
+ swap_prioritized_items(list, i, j);
74
+ i = j;
75
+
76
+ } else {
77
+ return;
78
+ }
79
+ }
80
+ }
81
+
82
+ int next_prioritized_item(PrioritizedItemList list) {
83
+ PrioritizedItem item;
84
+
85
+ if (empty_prioritized_item_list(list)) {
86
+ return -1;
87
+ }
88
+
89
+ item = list->priorities[0];
90
+ swap_prioritized_items(list, 0, list->last);
91
+ list->last--;
92
+ reprioritize_right(list, 0);
93
+
94
+ return item->item;
95
+ }
96
+
97
+ void update_prioritized_item(PrioritizedItemList list, int item, int priority) {
98
+ int i = list->indices[item];
99
+ list->priorities[i]->priority = priority;
100
+
101
+ if (i <= list->last) {
102
+ reprioritize_left(list, i);
103
+ }
104
+ }
105
+
106
+ int get_priority(PrioritizedItemList list, int item) {
107
+ int index = list->indices[item];
108
+ return list->priorities[index]->priority;
109
+ }
110
+
111
+ // For debugging only
112
+ void print_prioritized_item_list(PrioritizedItemList list) {
113
+ for (int i = 0; i <= list->last; i++) {
114
+ if (i > 0) printf(", ");
115
+ printf("%d (%d)", list->priorities[i]->item, list->priorities[i]->priority);
116
+ }
117
+ printf("\n");
118
+ }
119
+
120
+ void free_prioritized_item_list(PrioritizedItemList list) {
121
+ for (int i = 0; i < list->capacity; i++) {
122
+ free(list->priorities[i]);
123
+ }
124
+
125
+ free(list->priorities);
126
+ free(list->indices);
127
+ free(list);
128
+ }
@@ -0,0 +1,39 @@
1
+ #ifndef PRIORITIZED_ITEM_LIST_H
2
+ #define PRIORITIZED_ITEM_LIST_H
3
+
4
+ #include <ruby.h>
5
+
6
+ struct PrioritizedItemStruct;
7
+ typedef struct PrioritizedItemStruct* PrioritizedItem;
8
+
9
+ typedef struct PrioritizedItemStruct {
10
+ int item;
11
+ int priority;
12
+ } PrioritizedItemStruct;
13
+
14
+ //////////////////////////////////////////////////////////////////////////////////////
15
+
16
+ struct PrioritizedItemListStruct;
17
+ typedef struct PrioritizedItemListStruct* PrioritizedItemList;
18
+
19
+ typedef struct PrioritizedItemListStruct {
20
+ PrioritizedItem *priorities;
21
+ int *indices;
22
+ int capacity;
23
+ int last;
24
+ } PrioritizedItemListStruct;
25
+
26
+ //////////////////////////////////////////////////////////////////////////////////////
27
+
28
+ PrioritizedItemList make_prioritized_item_list(int capacity);
29
+ bool empty_prioritized_item_list(PrioritizedItemList list);
30
+ bool in_prioritized_item_list(PrioritizedItemList list, int item);
31
+ int next_prioritized_item(PrioritizedItemList list);
32
+ void update_prioritized_item(PrioritizedItemList list, int item, int priority);
33
+ void print_prioritized_item_list(PrioritizedItemList list);
34
+ int get_priority(PrioritizedItemList list, int item);
35
+ void free_prioritized_item_list(PrioritizedItemList list);
36
+
37
+ //////////////////////////////////////////////////////////////////////////////////////
38
+
39
+ #endif
@@ -0,0 +1,17 @@
1
+ module DijkstraFast
2
+ ##
3
+ # The "best path" from applying Dijkstra's algorithm contains both the ordered
4
+ # list of nodes travelled as well as the total distance travelled.
5
+ ##
6
+ class BestPath
7
+
8
+ attr_reader :path
9
+ attr_accessor :distance
10
+
11
+ def initialize
12
+ @path = []
13
+ @distance = 0
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,63 @@
1
+ module DijkstraFast
2
+ ##
3
+ # Dijkstra's algorithm finds the shortest "distance" between two items within a
4
+ # collection. For any two items within that collection that are "connected"
5
+ # there should be an associated "distance" between them. We can represent this
6
+ # collection of items as nodes in a directed graph, and we can represent the
7
+ # associated connections as weighted edges.
8
+ #
9
+ # = Example
10
+ #
11
+ # graph = DijkstraFast::Graph.new
12
+ # graph.add("A", "B", distance: 5)
13
+ # graph.add("A", "C", distance: 8)
14
+ # graph.add("B", "C", distance: 2)
15
+ # best_path = graph.shortest_path("A", "C")
16
+ # best_path.path
17
+ #
18
+ # => ["A", "B", "C"]
19
+ #
20
+ # best_path.distance
21
+ #
22
+ # => 7
23
+ #
24
+ ##
25
+ class Graph
26
+
27
+ def initialize
28
+ @nodes = {}
29
+ end
30
+
31
+ # Adds a weighted edge to the graph. This represents a possible path from the
32
+ # source item to the destination item with corresponding "distance."
33
+ # @param source [Object] Any Ruby object that represents the source item
34
+ # @param dest [Object] Any Ruby object that represents the destination item
35
+ # @param distance [Integer] Optional distance between source and destination.
36
+ # If not provided, a default distance of `1` is used.
37
+ # @return [nil]
38
+ def add(source, dest, distance: 1)
39
+ _add_edge(node(source), node(dest), distance) unless source == dest
40
+ end
41
+
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
54
+ end
55
+
56
+ private
57
+
58
+ def node(obj)
59
+ @nodes[obj] ||= @nodes.size # Auto-increment id
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,6 @@
1
+ module DijkstraFast
2
+ ##
3
+ # Raised when no path exists between the given source and destination items.
4
+ ##
5
+ class NoPathExistsError < StandardError; end
6
+ end
@@ -0,0 +1,6 @@
1
+ module DijkstraFast
2
+
3
+ # Current gem version
4
+ VERSION = '1.4.2'
5
+
6
+ end
@@ -0,0 +1,22 @@
1
+ ##
2
+ # Provides native implementation of Dijkstra's algorithm for finding the shortest
3
+ # path between two vertices in a large, sparse graph.
4
+ #
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
+ #
10
+ # @see README
11
+ # @see https://en.wikipedia.org/wiki/Dijkstra's_algorithm
12
+ ##
13
+ module DijkstraFast
14
+
15
+ autoload :BestPath, 'dijkstra_fast/best_path'
16
+ autoload :Graph, 'dijkstra_fast/graph'
17
+ autoload :NoPathExistsError, 'dijkstra_fast/no_path_exists_error'
18
+ autoload :VERSION, 'dijkstra_fast/version'
19
+
20
+ end
21
+
22
+ require 'dijkstra_fast/dijkstra_fast'
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dijkstra_fast
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.4.2
5
+ platform: ruby
6
+ authors:
7
+ - David McCullars
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
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'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
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'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yard
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: |
140
+ Native implementation of Dijkstra algorithm for finding the shortest path
141
+ between two vertices in a large, sparse graphs. Underlying algorithm is
142
+ implemented in C using a priority queue. Edges are represented using linked
143
+ lists rather than an adjacency matrix to reduce memory footprint when operating
144
+ on very large graphs where the average number of edges between nodes is
145
+ relatively small (e.g. < 1/10 the number of nodes). See
146
+ https://en.wikipedia.org/wiki/Dijkstra's_algorithm for additional information.
147
+ email:
148
+ - david.mccullars@gmail.com
149
+ executables: []
150
+ extensions:
151
+ - ext/dijkstra_fast/extconf.rb
152
+ extra_rdoc_files: []
153
+ files:
154
+ - ".codeclimate.yml"
155
+ - ".gitignore"
156
+ - ".rspec"
157
+ - ".rubocop.yml"
158
+ - ".ruby-version"
159
+ - ".travis.yml"
160
+ - CODE_OF_CONDUCT.md
161
+ - Gemfile
162
+ - LICENSE
163
+ - README.md
164
+ - Rakefile
165
+ - dijkstra_fast.gemspec
166
+ - ext/dijkstra_fast/dijkstra_fast.c
167
+ - ext/dijkstra_fast/dijkstra_graph.c
168
+ - ext/dijkstra_fast/dijkstra_graph.h
169
+ - ext/dijkstra_fast/extconf.rb
170
+ - ext/dijkstra_fast/prioritized_item_list.c
171
+ - ext/dijkstra_fast/prioritized_item_list.h
172
+ - lib/dijkstra_fast.rb
173
+ - lib/dijkstra_fast/best_path.rb
174
+ - lib/dijkstra_fast/graph.rb
175
+ - lib/dijkstra_fast/no_path_exists_error.rb
176
+ - lib/dijkstra_fast/version.rb
177
+ homepage: https://github.com/david-mccullars/dijkstra_fast
178
+ licenses:
179
+ - MIT
180
+ metadata: {}
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubygems_version: 3.2.32
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: "(Native) implementation of Dijkstra algorithm for large, sparse graphs"
200
+ test_files: []