shortest_path 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,3 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ - 2.0.0
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 [![Build Status](https://travis-ci.org/dryade/shortest_path.png)](http://travis-ci.org/dryade/shortest_path?branch=master) [![Dependency Status](https://gemnasium.com/dryade/shortest_path.png)](https://gemnasium.com/dryade/shortest_path) [![Code Climate](https://codeclimate.com/github/dryade/shortest_path.png)](https://codeclimate.com/github/dryade/shortest_path)
1
+ # Shortest Path
2
+ [![Build Status](https://travis-ci.org/dryade/shortest_path.png)](http://travis-ci.org/dryade/shortest_path?branch=master) [![Dependency Status](https://gemnasium.com/dryade/shortest_path.png)](https://gemnasium.com/dryade/shortest_path) [![Code Climate](https://codeclimate.com/github/dryade/shortest_path.png)](https://codeclimate.com/github/dryade/shortest_path) [![Coverage Status](https://img.shields.io/coveralls/dryade/shortest_path.svg)](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
@@ -1,4 +1,4 @@
1
- require 'pqueue'
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
- visited = {}
78
- pq = PQueue.new do |x,y|
79
- search_heuristic(x) < search_heuristic(y)
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.size != 0 && not_found
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, context[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] > shortest_distances[v] + weights[w]) and
102
- follow_way?(v, w, weights[w], context[v])
103
- shortest_distances[w] = shortest_distances[v] + weights[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
- context[w] = refresh_context( w, context[v])
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
@@ -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
- visited = {}
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
- visited[source] = true
48
+ pq.push(source, 0)
49
+ visit source
40
50
  shortest_distances[source] = 0
41
51
 
42
- while pq.size != 0
52
+ while !pq.empty?
43
53
  v = pq.pop
44
- visited[v] = true
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[w] and
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
@@ -1,3 +1,3 @@
1
1
  module ShortestPath
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "rake"
23
23
  s.add_development_dependency "rspec"
24
24
 
25
- s.add_dependency "pqueue"
25
+ s.add_dependency "priority_queue_cxx"
26
26
 
27
27
  end
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  class TestContextualFinder < ShortestPath::Finder
4
4
  def refresh_context( node, context)
5
- count = context[:edges_count] ? context[:edges_count] : 0
6
- return { :edges_count => (count + 1)}
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
- :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} }
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
- # some (optional) config here
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
- hash: 25
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
- date: 2013-08-12 00:00:00 Z
21
- dependencies:
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
- - !ruby/object:Gem::Dependency
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
- hash: 3
44
- segments:
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
- - !ruby/object:Gem::Dependency
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
- hash: 3
58
- segments:
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
- - !ruby/object:Gem::Dependency
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
- hash: 3
72
- segments:
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
- - !ruby/object:Gem::Dependency
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
- hash: 3
86
- segments:
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
- - !ruby/object:Gem::Dependency
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
- hash: 3
100
- segments:
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
- name: pqueue
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
- hash: 3
148
- segments:
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ segments:
149
150
  - 0
150
- version: "0"
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
- hash: 3
157
- segments:
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ segments:
158
159
  - 0
159
- version: "0"
160
+ hash: 1341351258851856295
160
161
  requirements: []
161
-
162
162
  rubyforge_project:
163
- rubygems_version: 1.8.24
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
-