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 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
-