shortest_path 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.3-head
File without changes
data/README.md CHANGED
@@ -1,18 +1,37 @@
1
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)
2
2
 
3
- A* ruby implementation to find shortest path and map in a graph.
3
+ A* ruby implementation to find shortest path and map in a graph with :
4
+ - a timeout to stop research when duration > timeout
5
+ - a context in a hash for each point in the graph
6
+ - the possibility to override default methods
7
+
4
8
 
5
9
  Requirements
6
10
  ------------
7
11
 
8
- This code has been run and tested on Ruby 1.8 and 1.9
12
+ This code has been run and tested on Ruby 1.9
13
+
14
+ External Deps
15
+ -------------
16
+ On Debian/Ubuntu/Kubuntu OS :
17
+ ```sh
18
+ sudo apt-get install git
19
+ ```
9
20
 
10
21
  Installation
11
22
  ------------
12
23
 
13
24
  This package is available in RubyGems and can be installed with:
14
-
15
- gem install shortest_path
25
+ ```sh
26
+ gem install shortest_path
27
+ ```
28
+
29
+ Test
30
+ ----
31
+
32
+ ```sh
33
+ bundle exec rake spec
34
+ ```
16
35
 
17
36
  More Information
18
37
  ----------------
@@ -23,8 +42,40 @@ There is extensive usage documentation available [on the wiki](https://github.co
23
42
  Example Usage
24
43
  -------------
25
44
 
45
+ Create a basic shortest path finder :
46
+ ```ruby
47
+ # Create a graph
48
+ graph = { :a => { :e => 3, :b => 1, :c => 3},
49
+ :b => {:e => 1, :a => 1, :c => 3, :d => 5},
50
+ :c => {:a => 3, :b => 3, :d => 1, :s => 3},
51
+ :d => {:b => 5, :c => 1, :s => 1},
52
+ :e => {:a => 3, :b => 1},
53
+ :s => {:c => 3, :d => 1} }
54
+ }
55
+
56
+ # Create a finder
57
+ finder = ShortestPath::Finder.new(:a, :e).tap do |shortest_path|
58
+ shortest_path.ways_finder = Proc.new { |node| graph[node] }
59
+ end
60
+
61
+ # Change the timeout in seconds
62
+ finder.timeout = 2
63
+
64
+ # Call graph result
65
+ finder.path
66
+
67
+ ```
68
+
69
+ Overwrite shortest path finder :
70
+ ```ruby
71
+
72
+ # TODO : Class that overwrites shortest path finder
26
73
  ...
27
74
 
75
+
76
+ ```
77
+
78
+
28
79
  License
29
80
  -------
30
81
 
@@ -14,7 +14,11 @@ module ShortestPath
14
14
  # Example : { :a => 2, :b => 3 }
15
15
  attr_accessor :ways_finder
16
16
 
17
- def ways(node)
17
+ def refresh_context( node, context)
18
+ {}
19
+ end
20
+
21
+ def ways(node, context={})
18
22
  ways_finder.call node
19
23
  end
20
24
 
@@ -26,17 +30,26 @@ module ShortestPath
26
30
  @previous ||= {}
27
31
  end
28
32
 
33
+ # @context is a hash
34
+ # each node is related to an hash defining the context
35
+ # context is specific to the path solution between departure dans target node
36
+ #
37
+ def context
38
+ @context ||= {}
39
+ end
40
+
29
41
  def search_heuristic(node)
30
42
  shortest_distances[node]
31
43
  end
32
44
 
33
- def follow_way?(node, destination, weight)
45
+ def follow_way?(node, destination, weight, context={})
34
46
  true
35
47
  end
36
48
 
49
+ # timeout is in seconds
37
50
  attr_accessor :timeout
38
51
  attr_reader :begin_at, :end_at
39
-
52
+
40
53
  def timeout?
41
54
  timeout and (duration > timeout)
42
55
  end
@@ -47,7 +60,7 @@ module ShortestPath
47
60
  end
48
61
 
49
62
  def visited?(node)
50
- @visited[node]
63
+ @visited[node]
51
64
  end
52
65
 
53
66
  def visit(node)
@@ -60,15 +73,16 @@ module ShortestPath
60
73
 
61
74
  def path_without_cache
62
75
  @begin_at = Time.now
63
-
76
+
64
77
  visited = {}
65
- pq = PQueue.new do |x,y|
78
+ pq = PQueue.new do |x,y|
66
79
  search_heuristic(x) < search_heuristic(y)
67
80
  end
68
81
 
69
- pq.push(source)
82
+ pq.push( source)
70
83
  visit source
71
84
  shortest_distances[source] = 0
85
+ context[source] = {}
72
86
 
73
87
  not_found = !found?(source)
74
88
 
@@ -79,16 +93,17 @@ module ShortestPath
79
93
  not_found = !found?(v)
80
94
  visit v
81
95
 
82
- weights = ways(v)
96
+ weights = ways(v, context[v])
83
97
  if weights
84
98
  weights.keys.each do |w|
85
99
  if !visited?(w) and
86
100
  weights[w] and
87
- ( shortest_distances[w].nil? || shortest_distances[w] > shortest_distances[v] + weights[w]) and
88
- follow_way?(v, w, weights[w])
101
+ ( shortest_distances[w].nil? || shortest_distances[w] > shortest_distances[v] + weights[w]) and
102
+ follow_way?(v, w, weights[w], context[v])
89
103
  shortest_distances[w] = shortest_distances[v] + weights[w]
90
104
  previous[w] = v
91
- pq.push(w)
105
+ context[w] = refresh_context( w, context[v])
106
+ pq.push( w)
92
107
  end
93
108
  end
94
109
  end
@@ -1,3 +1,3 @@
1
1
  module ShortestPath
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,5 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
+ class TestContextualFinder < ShortestPath::Finder
4
+ def refresh_context( node, context)
5
+ count = context[:edges_count] ? context[:edges_count] : 0
6
+ return { :edges_count => (count + 1)}
7
+ end
8
+
9
+ def follow_way?(node, destination, weight, context={})
10
+ return context[:edges_count].nil? || context[:edges_count] < 3
11
+ end
12
+
13
+ end
14
+
3
15
  describe ShortestPath::Finder do
4
16
  let(:graph) {
5
17
  { :a => { :e => 3, :b => 1, :c => 3},
@@ -10,6 +22,18 @@ describe ShortestPath::Finder do
10
22
  :s => {:c => 3, :d => 1} }
11
23
  }
12
24
 
25
+ def contextual_shortest_path(source, destination, given_graph = graph)
26
+ TestContextualFinder.new(source, destination).tap do |shortest_path|
27
+ shortest_path.ways_finder = Proc.new { |node| given_graph[node] }
28
+ end.path
29
+ end
30
+
31
+ context "when using an edge_count filter in context " do
32
+ it "should find shortest path in an exemple" do
33
+ contextual_shortest_path(:e, :s).should == [:e, :b, :c, :s]
34
+ end
35
+ end
36
+
13
37
  def shortest_path(source, destination, given_graph = graph)
14
38
  ShortestPath::Finder.new(source, destination).tap do |shortest_path|
15
39
  shortest_path.ways_finder = Proc.new { |node| given_graph[node] }
@@ -38,16 +62,16 @@ describe ShortestPath::Finder do
38
62
  shortest_path(:e, :s, not_connex).should be_empty
39
63
  end
40
64
 
41
- subject {
65
+ subject {
42
66
  ShortestPath::Finder.new(:e, :s).tap do |shortest_path|
43
67
  shortest_path.ways_finder = Proc.new { |node| graph[node] }
44
68
  end
45
69
  }
46
70
 
47
71
  describe "begin_at" do
48
-
72
+
49
73
  let(:expected_time) { Time.now }
50
-
74
+
51
75
  it "should be defined when path starts" do
52
76
  Time.stub :now => expected_time
53
77
  subject.path
@@ -57,9 +81,9 @@ describe ShortestPath::Finder do
57
81
  end
58
82
 
59
83
  describe "end_at" do
60
-
84
+
61
85
  let(:expected_time) { Time.now }
62
-
86
+
63
87
  it "should be defined when path ends" do
64
88
  Time.stub :now => expected_time
65
89
  subject.path
@@ -69,7 +93,7 @@ describe ShortestPath::Finder do
69
93
  end
70
94
 
71
95
  describe "duration" do
72
-
96
+
73
97
  it "should be nil before path is search" do
74
98
  subject.duration.should be_nil
75
99
  end
@@ -99,12 +123,12 @@ describe ShortestPath::Finder do
99
123
  subject.timeout = nil
100
124
  subject.should_not be_timeout
101
125
  end
102
-
126
+
103
127
  it "should be false when duration is lower than timeout" do
104
128
  subject.stub :duration => (subject.timeout - 1)
105
129
  subject.should_not be_timeout
106
130
  end
107
-
131
+
108
132
  it "should be true when duration is greater than timeout" do
109
133
  subject.stub :duration => (subject.timeout + 1)
110
134
  subject.should be_timeout
@@ -113,7 +137,7 @@ describe ShortestPath::Finder do
113
137
  end
114
138
 
115
139
  describe "path" do
116
-
140
+
117
141
  it "should raise a Timeout::Error when timeout?" do
118
142
  subject.stub :timeout? => true
119
143
  lambda { subject.path }.should raise_error(ShortestPath::TimeoutError)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shortest_path
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alban Peignier
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2013-05-07 00:00:00 Z
20
+ date: 2013-08-12 00:00:00 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  type: :development
@@ -116,10 +116,11 @@ extra_rdoc_files: []
116
116
 
117
117
  files:
118
118
  - .gitignore
119
+ - .rvmrc
119
120
  - .travis.yml
120
121
  - Gemfile
121
122
  - Guardfile
122
- - LICENSE.txt
123
+ - MIT-LICENSE
123
124
  - README.md
124
125
  - Rakefile
125
126
  - lib/shortest_path.rb