shortest_path 0.0.3 → 0.0.4
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.
- data/.travis.yml +1 -0
- data/Gemfile +3 -1
- data/README.md +6 -10
- data/lib/shortest_path/finder.rb +58 -18
- data/lib/shortest_path/map.rb +19 -9
- data/lib/shortest_path/version.rb +1 -1
- data/shortest_path.gemspec +1 -1
- data/spec/shortest_path/finder_spec.rb +42 -9
- data/spec/spec_helper.rb +4 -1
- metadata +105 -106
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -3,9 +3,11 @@ source "http://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in shortest_path.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
gem 'coveralls', require: false
|
7
|
+
|
6
8
|
group :development do
|
7
9
|
group :linux do
|
8
10
|
gem 'rb-inotify', :require => RUBY_PLATFORM.include?('linux') && 'rb-inotify'
|
9
11
|
gem 'rb-fsevent', :require => RUBY_PLATFORM.include?('darwin') && 'rb-fsevent'
|
10
12
|
end
|
11
|
-
end
|
13
|
+
end
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# Shortest Path
|
1
|
+
# Shortest Path
|
2
|
+
[](http://travis-ci.org/dryade/shortest_path?branch=master) [](https://gemnasium.com/dryade/shortest_path) [](https://codeclimate.com/github/dryade/shortest_path) [](https://coveralls.io/r/dryade/shortest_path)
|
2
3
|
|
3
4
|
A* ruby implementation to find shortest path and map in a graph with :
|
4
5
|
- a timeout to stop research when duration > timeout
|
@@ -9,7 +10,7 @@ A* ruby implementation to find shortest path and map in a graph with :
|
|
9
10
|
Requirements
|
10
11
|
------------
|
11
12
|
|
12
|
-
This code has been run and tested on Ruby 1.9
|
13
|
+
This code has been run and tested on Ruby 1.9 or later
|
13
14
|
|
14
15
|
External Deps
|
15
16
|
-------------
|
@@ -18,6 +19,8 @@ On Debian/Ubuntu/Kubuntu OS :
|
|
18
19
|
sudo apt-get install git
|
19
20
|
```
|
20
21
|
|
22
|
+
gcc is for priority queue.
|
23
|
+
|
21
24
|
Installation
|
22
25
|
------------
|
23
26
|
|
@@ -66,14 +69,7 @@ finder.path
|
|
66
69
|
|
67
70
|
```
|
68
71
|
|
69
|
-
Overwrite shortest path finder :
|
70
|
-
```ruby
|
71
|
-
|
72
|
-
# TODO : Class that overwrites shortest path finder
|
73
|
-
...
|
74
|
-
|
75
|
-
|
76
|
-
```
|
72
|
+
Overwrite shortest path finder : Find an example in [activeroad project](https://github.com/dryade/activeroad/blob/master/lib/active_road/shortest_path/finder.rb)
|
77
73
|
|
78
74
|
|
79
75
|
License
|
data/lib/shortest_path/finder.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'fc'
|
2
2
|
|
3
3
|
module ShortestPath
|
4
4
|
class Finder
|
@@ -15,7 +15,7 @@ module ShortestPath
|
|
15
15
|
attr_accessor :ways_finder
|
16
16
|
|
17
17
|
def refresh_context( node, context)
|
18
|
-
|
18
|
+
{}
|
19
19
|
end
|
20
20
|
|
21
21
|
def ways(node, context={})
|
@@ -73,45 +73,85 @@ module ShortestPath
|
|
73
73
|
|
74
74
|
def path_without_cache
|
75
75
|
@begin_at = Time.now
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
pq.push( source)
|
76
|
+
|
77
|
+
pq = ::FastContainers::PriorityQueue.new(:min)
|
78
|
+
# PQueue.new do |x,y|
|
79
|
+
# search_heuristic(x) < search_heuristic(y)
|
80
|
+
# end
|
81
|
+
pq.push(source, 0)
|
83
82
|
visit source
|
84
83
|
shortest_distances[source] = 0
|
85
|
-
context[source] = {}
|
86
84
|
|
87
85
|
not_found = !found?(source)
|
88
86
|
|
89
|
-
while pq.
|
87
|
+
while !pq.empty? && not_found
|
90
88
|
raise TimeoutError if timeout?
|
91
89
|
|
92
90
|
v = pq.pop
|
93
91
|
not_found = !found?(v)
|
94
|
-
visit v
|
95
92
|
|
96
|
-
weights = ways(v
|
93
|
+
weights = ways(v)
|
97
94
|
if weights
|
98
95
|
weights.keys.each do |w|
|
96
|
+
w_distance = shortest_distances[v] + weights[w]
|
97
|
+
|
99
98
|
if !visited?(w) and
|
100
99
|
weights[w] and
|
101
|
-
( shortest_distances[w].nil? || shortest_distances[w] >
|
102
|
-
follow_way?(v, w, weights[w]
|
103
|
-
shortest_distances[w] =
|
100
|
+
( shortest_distances[w].nil? || shortest_distances[w] > w_distance) and
|
101
|
+
follow_way?(v, w, weights[w])
|
102
|
+
shortest_distances[w] = w_distance
|
104
103
|
previous[w] = v
|
105
|
-
|
106
|
-
pq.push( w)
|
104
|
+
pq.push(w, search_heuristic(w) )
|
107
105
|
end
|
108
106
|
end
|
109
107
|
end
|
110
108
|
end
|
111
109
|
|
112
110
|
@end_at = Time.now
|
111
|
+
#puts previous.inspect
|
113
112
|
not_found ? [] : sorted_array
|
114
113
|
end
|
114
|
+
|
115
|
+
# def path_without_cache
|
116
|
+
# @begin_at = Time.now
|
117
|
+
|
118
|
+
# pq = PQueue.new do |x,y|
|
119
|
+
# search_heuristic(x) < search_heuristic(y)
|
120
|
+
# end
|
121
|
+
|
122
|
+
# pq.push( source)
|
123
|
+
# visit source
|
124
|
+
# shortest_distances[source] = 0
|
125
|
+
# context[source] = {}
|
126
|
+
|
127
|
+
# not_found = !found?(source)
|
128
|
+
|
129
|
+
# while pq.size != 0 && not_found
|
130
|
+
# raise TimeoutError if timeout?
|
131
|
+
|
132
|
+
# v = pq.pop
|
133
|
+
# not_found = !found?(v)
|
134
|
+
# visit v
|
135
|
+
|
136
|
+
# weights = ways(v, context[v])
|
137
|
+
# if weights
|
138
|
+
# weights.keys.each do |w|
|
139
|
+
# if !visited?(w) and
|
140
|
+
# weights[w] and
|
141
|
+
# ( shortest_distances[w].nil? || shortest_distances[w] > shortest_distances[v] + weights[w]) and
|
142
|
+
# follow_way?(v, w, weights[w], context[v])
|
143
|
+
# shortest_distances[w] = shortest_distances[v] + weights[w]
|
144
|
+
# previous[w] = v
|
145
|
+
# context[w] = refresh_context( w, context[v])
|
146
|
+
# pq.push( w)
|
147
|
+
# end
|
148
|
+
# end
|
149
|
+
# end
|
150
|
+
# end
|
151
|
+
|
152
|
+
# @end_at = Time.now
|
153
|
+
# not_found ? [] : sorted_array
|
154
|
+
# end
|
115
155
|
|
116
156
|
def path_with_cache
|
117
157
|
@path ||= path_without_cache
|
data/lib/shortest_path/map.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'fc'
|
2
|
+
|
1
3
|
module ShortestPath
|
2
4
|
class Map
|
3
5
|
|
@@ -6,6 +8,7 @@ module ShortestPath
|
|
6
8
|
|
7
9
|
def initialize(source)
|
8
10
|
@source = source
|
11
|
+
@visited = {}
|
9
12
|
end
|
10
13
|
|
11
14
|
# Should return a map with accessible nodes and associated weight
|
@@ -28,33 +31,40 @@ module ShortestPath
|
|
28
31
|
shortest_distances[node]
|
29
32
|
end
|
30
33
|
|
34
|
+
def visited?(node)
|
35
|
+
@visited[node]
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit(node)
|
39
|
+
@visited[node] = true
|
40
|
+
end
|
41
|
+
|
31
42
|
def map
|
32
43
|
@shortest_distances = {}
|
33
44
|
@previous = {}
|
34
45
|
|
35
|
-
|
36
|
-
pq = PQueue.new { |x,y| search_heuristic(x) < search_heuristic(y) }
|
46
|
+
pq = ::FastContainers::PriorityQueue.new(:min)
|
37
47
|
|
38
|
-
pq.push(source)
|
39
|
-
|
48
|
+
pq.push(source, 0)
|
49
|
+
visit source
|
40
50
|
shortest_distances[source] = 0
|
41
51
|
|
42
|
-
while pq.
|
52
|
+
while !pq.empty?
|
43
53
|
v = pq.pop
|
44
|
-
|
54
|
+
visit v
|
45
55
|
|
46
56
|
weights = ways(v)
|
47
57
|
if weights
|
48
58
|
weights.keys.each do |w|
|
49
59
|
w_distance = shortest_distances[v] + weights[w]
|
50
|
-
|
51
|
-
if !visited
|
60
|
+
|
61
|
+
if !visited?(w) and
|
52
62
|
weights[w] and
|
53
63
|
( shortest_distances[w].nil? || shortest_distances[w] > w_distance) and
|
54
64
|
follow_way?(v, w, weights[w])
|
55
65
|
shortest_distances[w] = w_distance
|
56
66
|
previous[w] = v
|
57
|
-
pq.push(w)
|
67
|
+
pq.push(w, search_heuristic(w) )
|
58
68
|
end
|
59
69
|
end
|
60
70
|
end
|
data/shortest_path.gemspec
CHANGED
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
class TestContextualFinder < ShortestPath::Finder
|
4
4
|
def refresh_context( node, context)
|
5
|
-
|
6
|
-
|
5
|
+
count = context[:edges_count] ? context[:edges_count] : 0
|
6
|
+
return { :edges_count => (count + 1)}
|
7
7
|
end
|
8
8
|
|
9
9
|
def follow_way?(node, destination, weight, context={})
|
@@ -14,23 +14,56 @@ end
|
|
14
14
|
|
15
15
|
describe ShortestPath::Finder do
|
16
16
|
let(:graph) {
|
17
|
-
{ :a => { :e => 3, :b => 1, :c => 3},
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
{ :a => { :e => 3, :b => 1, :c => 3 },
|
18
|
+
:b => { :e => 1, :a => 1, :c => 3, :d => 5 },
|
19
|
+
:c => { :a => 3, :b => 3, :d => 1, :s => 3 },
|
20
|
+
:d => { :b => 5, :c => 1, :s => 1 },
|
21
|
+
:e => { :a => 3, :b => 1 },
|
22
|
+
:s => { :c => 3, :d => 1 } }
|
23
23
|
}
|
24
24
|
|
25
|
+
def graph_sample( size)
|
26
|
+
hash = {}
|
27
|
+
0.upto( size ) do |i|
|
28
|
+
0.upto( size ) do |j|
|
29
|
+
hash[ "#{i}-#{j}" ] = {} if hash[ "#{i}-#{j}" ].nil?
|
30
|
+
node_neighbors = hash[ "#{i}-#{j}" ]
|
31
|
+
if i<size
|
32
|
+
node_neighbors[ "#{i+1}-#{j}" ] = 1
|
33
|
+
|
34
|
+
# reverse link
|
35
|
+
hash[ "#{i+1}-#{j}" ] = {} if hash[ "#{i+1}-#{j}" ].nil?
|
36
|
+
hash[ "#{i+1}-#{j}" ][ "#{i}-#{j}" ] = 1
|
37
|
+
end
|
38
|
+
if j<size
|
39
|
+
node_neighbors[ "#{i}-#{j+1}" ] = 1
|
40
|
+
|
41
|
+
# reverse link
|
42
|
+
hash[ "#{i}-#{j+1}" ] = {} if hash[ "#{i}-#{j+1}" ].nil?
|
43
|
+
hash[ "#{i}-#{j+1}" ][ "#{i}-#{j}" ] = 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
hash
|
48
|
+
end
|
49
|
+
|
25
50
|
def contextual_shortest_path(source, destination, given_graph = graph)
|
26
51
|
TestContextualFinder.new(source, destination).tap do |shortest_path|
|
27
52
|
shortest_path.ways_finder = Proc.new { |node| given_graph[node] }
|
28
53
|
end.path
|
29
54
|
end
|
30
55
|
|
56
|
+
it "should produce test graph" do
|
57
|
+
my_graph = graph_sample(600)
|
58
|
+
start = Time.now
|
59
|
+
result = expect(shortest_path( "150-150", "300-300", my_graph))
|
60
|
+
puts "cost= #{Time.now-start}"
|
61
|
+
puts result.inspect
|
62
|
+
end
|
63
|
+
|
31
64
|
context "when using an edge_count filter in context " do
|
32
65
|
it "should find shortest path in an exemple" do
|
33
|
-
contextual_shortest_path(:e, :s).should == [:e, :b, :c, :s]
|
66
|
+
contextual_shortest_path(:e, :s).should == [:e, :b, :c, :d, :s]
|
34
67
|
end
|
35
68
|
end
|
36
69
|
|
data/spec/spec_helper.rb
CHANGED
@@ -5,8 +5,11 @@ require 'rspec'
|
|
5
5
|
|
6
6
|
require 'shortest_path' # and any other gems you need
|
7
7
|
|
8
|
+
require 'coveralls'
|
9
|
+
Coveralls.wear!
|
10
|
+
|
8
11
|
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
9
12
|
|
10
13
|
RSpec.configure do |config|
|
11
|
-
|
14
|
+
|
12
15
|
end
|
metadata
CHANGED
@@ -1,120 +1,123 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: shortest_path
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 3
|
10
|
-
version: 0.0.3
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Alban Peignier
|
14
9
|
- Marc Florisson
|
15
10
|
- Luc Donnet
|
16
11
|
autorequire:
|
17
12
|
bindir: bin
|
18
13
|
cert_chain: []
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
- !ruby/object:Gem::Dependency
|
23
|
-
type: :development
|
24
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 3
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
33
|
-
requirement: *id001
|
34
|
-
prerelease: false
|
14
|
+
date: 2014-05-14 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
35
17
|
name: guard
|
36
|
-
|
37
|
-
type: :development
|
38
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
39
19
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
|
45
|
-
- 0
|
46
|
-
version: "0"
|
47
|
-
requirement: *id002
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :development
|
48
25
|
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
32
|
+
- !ruby/object:Gem::Dependency
|
49
33
|
name: guard-bundler
|
50
|
-
|
51
|
-
type: :development
|
52
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
53
35
|
none: false
|
54
|
-
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
|
58
|
-
|
59
|
-
- 0
|
60
|
-
version: "0"
|
61
|
-
requirement: *id003
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
62
41
|
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
63
49
|
name: guard-rspec
|
64
|
-
|
65
|
-
type: :development
|
66
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
67
51
|
none: false
|
68
|
-
requirements:
|
69
|
-
- -
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
|
72
|
-
|
73
|
-
- 0
|
74
|
-
version: "0"
|
75
|
-
requirement: *id004
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :development
|
76
57
|
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
- !ruby/object:Gem::Dependency
|
77
65
|
name: rake
|
78
|
-
|
79
|
-
type: :development
|
80
|
-
version_requirements: &id005 !ruby/object:Gem::Requirement
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
81
67
|
none: false
|
82
|
-
requirements:
|
83
|
-
- -
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
|
86
|
-
|
87
|
-
- 0
|
88
|
-
version: "0"
|
89
|
-
requirement: *id005
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
type: :development
|
90
73
|
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
- !ruby/object:Gem::Dependency
|
91
81
|
name: rspec
|
92
|
-
|
93
|
-
type: :runtime
|
94
|
-
version_requirements: &id006 !ruby/object:Gem::Requirement
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
95
83
|
none: false
|
96
|
-
requirements:
|
97
|
-
- -
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
|
100
|
-
|
101
|
-
- 0
|
102
|
-
version: "0"
|
103
|
-
requirement: *id006
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
104
89
|
prerelease: false
|
105
|
-
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: priority_queue_cxx
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
106
112
|
description: A* ruby implementation to find shortest path and map
|
107
|
-
email:
|
113
|
+
email:
|
108
114
|
- alban@tryphon.eu
|
109
115
|
- mflorisson@cityway.fr
|
110
116
|
- luc.donnet@free.fr
|
111
117
|
executables: []
|
112
|
-
|
113
118
|
extensions: []
|
114
|
-
|
115
119
|
extra_rdoc_files: []
|
116
|
-
|
117
|
-
files:
|
120
|
+
files:
|
118
121
|
- .gitignore
|
119
122
|
- .rvmrc
|
120
123
|
- .travis.yml
|
@@ -133,36 +136,32 @@ files:
|
|
133
136
|
- spec/spec_helper.rb
|
134
137
|
homepage: http://github.com/dryade/shortest_path
|
135
138
|
licenses: []
|
136
|
-
|
137
139
|
post_install_message:
|
138
140
|
rdoc_options: []
|
139
|
-
|
140
|
-
require_paths:
|
141
|
+
require_paths:
|
141
142
|
- lib
|
142
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
144
|
none: false
|
144
|
-
requirements:
|
145
|
-
- -
|
146
|
-
- !ruby/object:Gem::Version
|
147
|
-
|
148
|
-
segments:
|
145
|
+
requirements:
|
146
|
+
- - ! '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
segments:
|
149
150
|
- 0
|
150
|
-
|
151
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
hash: 1341351258851856295
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
153
|
none: false
|
153
|
-
requirements:
|
154
|
-
- -
|
155
|
-
- !ruby/object:Gem::Version
|
156
|
-
|
157
|
-
segments:
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
segments:
|
158
159
|
- 0
|
159
|
-
|
160
|
+
hash: 1341351258851856295
|
160
161
|
requirements: []
|
161
|
-
|
162
162
|
rubyforge_project:
|
163
|
-
rubygems_version: 1.8.
|
163
|
+
rubygems_version: 1.8.23
|
164
164
|
signing_key:
|
165
165
|
specification_version: 3
|
166
166
|
summary: Ruby library to find shortest path(s) in a graph
|
167
167
|
test_files: []
|
168
|
-
|