shortest-path 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/lib/shortest/path.rb +3 -6
- data/lib/shortest/path/astar.rb +60 -0
- data/lib/shortest/path/general.rb +38 -0
- data/lib/shortest/path/priority_queue.rb +33 -0
- data/lib/shortest/path/version.rb +1 -1
- data/shortest-path.gemspec +2 -1
- data/spec/astar_spec.rb +41 -0
- data/spec/general_spec.rb +23 -0
- data/spec/priority_queue_spec.rb +20 -0
- data/spec/spec_helper.rb +3 -0
- metadata +30 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55f2e617f1bb69175440dd880744b84a5b0ed480
|
4
|
+
data.tar.gz: 575c55362f1987c38b1984457eab7c5314785f25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a6870f838329f9890c6094e1bf26457bb42312f01a093b02c5ab450c64093dd7f5b20ee6c5824085ab30005624a053a6d143dd0a3257356e9dc41e97b8f8b41
|
7
|
+
data.tar.gz: e7933a68e0c285de39138690130658171fb9bf230a4261bbaa4f6e87c5836132fe18eb92b92756af07f2ce21b6d5e8d176e3392b44b5033608709a9a0f5e825c
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/lib/shortest/path.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Shortest
|
2
|
+
module Path
|
3
|
+
class AStar
|
4
|
+
def initialize(dist,heur,graph,start,goal)
|
5
|
+
@dist=dist ; @heur=heur ; @graph=graph
|
6
|
+
@start=start ; @goal=goal
|
7
|
+
end
|
8
|
+
|
9
|
+
def search
|
10
|
+
closedset=[] ; openset=Shortest::Path::PriorityQueue.new ; came_from={}
|
11
|
+
start_g_score=0 ; start_f_score=start_g_score+@heur.call(@start,@goal)
|
12
|
+
g_score={@start => start_g_score} ; f_score={@start => start_f_score}
|
13
|
+
openset.add_with_priority(@start, start_f_score)
|
14
|
+
until openset.empty?
|
15
|
+
current=openset.pop
|
16
|
+
return reconstruct_path(came_from,@goal) if current==@goal
|
17
|
+
closedset<<current
|
18
|
+
@graph.neighbors(current).each do |neighbor|
|
19
|
+
next if closedset.include?(neighbor)
|
20
|
+
tentative_g_score=g_score[current]+@dist.call(current,neighbor)
|
21
|
+
if (not openset.include?(neighbor)) or (tentative_g_score < (g_score[neighbor]||Float::INFINITY))
|
22
|
+
came_from[neighbor]=current
|
23
|
+
g_score[neighbor]=tentative_g_score
|
24
|
+
f_score[neighbor]=tentative_g_score+@heur.call(neighbor,@goal)
|
25
|
+
if not openset.include?(neighbor)
|
26
|
+
openset.add_with_priority(neighbor, f_score[neighbor])
|
27
|
+
else
|
28
|
+
openset.change_priority(neighbor, f_score[neighbor])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return [] # failure!
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def reconstruct_path(came_from, current_node)
|
39
|
+
if came_from.include?(current_node)
|
40
|
+
p = reconstruct_path(came_from, came_from[current_node])
|
41
|
+
p << current_node
|
42
|
+
p
|
43
|
+
else
|
44
|
+
[current_node]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# `dist` function which calculates distance between two points
|
50
|
+
# `heur` heuristic function
|
51
|
+
# `graph` graph structure
|
52
|
+
# `start` start node
|
53
|
+
# `goal` goal node
|
54
|
+
def astar(dist,heur,graph,start,goal)
|
55
|
+
Shortest::Path::AStar.new(dist,heur,graph,start,goal).search
|
56
|
+
end
|
57
|
+
|
58
|
+
module_function :astar
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Shortest
|
2
|
+
module Path
|
3
|
+
class Edge
|
4
|
+
attr_accessor :src, :dst, :length
|
5
|
+
|
6
|
+
def initialize(src, dst, length)
|
7
|
+
@src=src
|
8
|
+
@dst=dst
|
9
|
+
@length=length
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Graph < Array
|
14
|
+
attr_reader :edges
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@edges=[]
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect(src, dst, length)
|
21
|
+
raise "No such vertex: #{src}" unless self.include?(src)
|
22
|
+
raise "No such vertex: #{dst}" unless self.include?(dst)
|
23
|
+
@edges.push Edge.new(src, dst, length)
|
24
|
+
end
|
25
|
+
|
26
|
+
def connect_mutually(vertex1, vertex2, length)
|
27
|
+
self.connect(vertex1, vertex2, length)
|
28
|
+
self.connect(vertex2, vertex1, length)
|
29
|
+
end
|
30
|
+
|
31
|
+
def neighbors(vertex)
|
32
|
+
neighbors = []
|
33
|
+
@edges.each{|edge| neighbors.push edge.dst if edge.src==vertex }
|
34
|
+
neighbors.uniq
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Shortest
|
2
|
+
module Path
|
3
|
+
class PriorityQueueItem
|
4
|
+
attr_reader :item, :priority
|
5
|
+
|
6
|
+
def initialize(item,priority)
|
7
|
+
@item = item ; @priority = priority
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class PriorityQueue
|
12
|
+
def initialize; @heap = [] end
|
13
|
+
|
14
|
+
def add_with_priority(object, priority)
|
15
|
+
item = PriorityQueueItem.new(object,priority)
|
16
|
+
@heap << item
|
17
|
+
sort_by_priority
|
18
|
+
end
|
19
|
+
|
20
|
+
def change_priority(object, priority)
|
21
|
+
@heap.select{|x| x.item==object}.first.priority=priority
|
22
|
+
sort_by_priority
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop; @heap.delete_at(0).item end
|
26
|
+
def empty?; @heap.empty? end
|
27
|
+
def include?(object); @heap.select{|x| x.item==object}.any? end
|
28
|
+
|
29
|
+
private
|
30
|
+
def sort_by_priority; @heap.sort!{ |x,y| x.priority <=> y.priority } end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/shortest-path.gemspec
CHANGED
@@ -19,5 +19,6 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
-
spec.add_development_dependency "
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
spec.add_development_dependency "debugger"
|
23
24
|
end
|
data/spec/astar_spec.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Point
|
4
|
+
attr_reader :x, :y
|
5
|
+
|
6
|
+
def initialize(x,y)
|
7
|
+
@x=x ; @y=y
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_graph(n)
|
12
|
+
graph=Shortest::Path::Graph.new
|
13
|
+
(0..n-1).each do |x|
|
14
|
+
(0..n-1).each do |y|
|
15
|
+
graph.push Point.new(x,y)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
(0..n*n-1).each do |i|
|
19
|
+
graph.connect_mutually(graph[i], graph[i+1], 1) unless (i+1)%n == 0
|
20
|
+
graph.connect_mutually(graph[i], graph[i+n], 1) unless i+1 > n*(n-1)
|
21
|
+
end
|
22
|
+
graph
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'AStar' do
|
26
|
+
before(:all) do
|
27
|
+
@graph=build_graph(3)
|
28
|
+
@p1=@graph[0] ; @p2=@graph[8]
|
29
|
+
dist = heur = ->(p1,p2){ dx=p1.x-p2.x ; dy=p1.y-p2.y ; Math.sqrt(dx*dx + dy*dy) }
|
30
|
+
@shortest=Shortest::Path.astar(dist, heur, @graph, @p1, @p2)
|
31
|
+
end
|
32
|
+
|
33
|
+
specify{ expect(@graph.size).to eq(9) }
|
34
|
+
specify{ expect(@graph.edges.size).to eq(24) }
|
35
|
+
specify{ expect(@shortest.size).to eq(5) }
|
36
|
+
specify{ expect(@shortest[0]).to eq(@graph[0]) }
|
37
|
+
specify{ expect(@shortest[1]).to eq(@graph[1]) }
|
38
|
+
specify{ expect(@shortest[2]).to eq(@graph[4]) }
|
39
|
+
specify{ expect(@shortest[3]).to eq(@graph[5]) }
|
40
|
+
specify{ expect(@shortest[4]).to eq(@graph[8]) }
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Graph' do
|
4
|
+
before(:all) do
|
5
|
+
@graph=Shortest::Path::Graph.new
|
6
|
+
(1..4).each{|x| @graph.push x}
|
7
|
+
expect(@graph.size).to eq(4)
|
8
|
+
@graph.connect_mutually 1, 2, 10
|
9
|
+
@graph.connect_mutually 1, 3, 10
|
10
|
+
@graph.connect_mutually 1, 4, 10
|
11
|
+
@graph.connect_mutually 2, 4, 10
|
12
|
+
|
13
|
+
@first_edge=@graph.edges.first
|
14
|
+
end
|
15
|
+
|
16
|
+
specify{ expect(@graph.neighbors(1).size).to eq(3) }
|
17
|
+
specify{ expect(@graph.neighbors(2).size).to eq(2) }
|
18
|
+
specify{ expect(@graph.neighbors(3).size).to eq(1) }
|
19
|
+
specify{ expect(@graph.neighbors(4).size).to eq(2) }
|
20
|
+
|
21
|
+
specify{ expect(@first_edge.src).to eq(1) }
|
22
|
+
specify{ expect(@first_edge.dst).to eq(2) }
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'PriorityQueue' do
|
4
|
+
before(:all) do
|
5
|
+
@queue=Shortest::Path::PriorityQueue.new
|
6
|
+
@queue.add_with_priority("A",1)
|
7
|
+
@queue.add_with_priority("D",4)
|
8
|
+
@queue.add_with_priority("C",3)
|
9
|
+
@queue.add_with_priority("B",2)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify{ expect(@queue).not_to be_empty }
|
13
|
+
specify{ expect(@queue.include?("A")).to eq(true) }
|
14
|
+
specify{ expect(@queue.pop).to eq("A") }
|
15
|
+
specify{ expect(@queue.pop).to eq("B") }
|
16
|
+
specify{ expect(@queue.pop).to eq("C") }
|
17
|
+
specify{ expect(@queue.pop).to eq("D") }
|
18
|
+
specify{ expect(@queue).to be_empty }
|
19
|
+
specify{ expect(@queue.include?("A")).to eq(false) }
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shortest-path
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Kurashvili
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,7 +25,21 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: debugger
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - '>='
|
@@ -46,13 +60,21 @@ extensions: []
|
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
48
62
|
- .gitignore
|
63
|
+
- .rspec
|
49
64
|
- Gemfile
|
50
65
|
- LICENSE.txt
|
51
66
|
- README.md
|
52
67
|
- Rakefile
|
53
68
|
- lib/shortest/path.rb
|
69
|
+
- lib/shortest/path/astar.rb
|
70
|
+
- lib/shortest/path/general.rb
|
71
|
+
- lib/shortest/path/priority_queue.rb
|
54
72
|
- lib/shortest/path/version.rb
|
55
73
|
- shortest-path.gemspec
|
74
|
+
- spec/astar_spec.rb
|
75
|
+
- spec/general_spec.rb
|
76
|
+
- spec/priority_queue_spec.rb
|
77
|
+
- spec/spec_helper.rb
|
56
78
|
homepage: http://github.com/georgian-se/shortest-path
|
57
79
|
licenses:
|
58
80
|
- MIT
|
@@ -77,4 +99,8 @@ rubygems_version: 2.3.0
|
|
77
99
|
signing_key:
|
78
100
|
specification_version: 4
|
79
101
|
summary: finding shortest path
|
80
|
-
test_files:
|
102
|
+
test_files:
|
103
|
+
- spec/astar_spec.rb
|
104
|
+
- spec/general_spec.rb
|
105
|
+
- spec/priority_queue_spec.rb
|
106
|
+
- spec/spec_helper.rb
|