jumoku 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/lib/jumoku.rb +4 -2
- data/lib/jumoku/version.rb +1 -1
- data/spec/raw_tree_spec.rb +353 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/tree_spec.rb +553 -0
- data/vendor/git/graphy/CREDITS.md +31 -0
- data/vendor/git/graphy/LICENSE +35 -0
- data/vendor/git/graphy/README.md +186 -0
- data/vendor/git/graphy/Rakefile +61 -0
- data/vendor/git/graphy/TODO.md +20 -0
- data/vendor/git/graphy/VERSION +1 -0
- data/vendor/git/graphy/examples/graph_self.rb +56 -0
- data/vendor/git/graphy/examples/module_graph.jpg +0 -0
- data/vendor/git/graphy/examples/module_graph.rb +14 -0
- data/vendor/git/graphy/examples/self_graph.jpg +0 -0
- data/vendor/git/graphy/examples/visualize.jpg +0 -0
- data/vendor/git/graphy/examples/visualize.rb +10 -0
- data/vendor/git/graphy/graphy.gemspec +149 -0
- data/vendor/git/graphy/lib/graphy.rb +90 -0
- data/vendor/git/graphy/lib/graphy/adjacency_graph.rb +224 -0
- data/vendor/git/graphy/lib/graphy/arc.rb +65 -0
- data/vendor/git/graphy/lib/graphy/arc_number.rb +52 -0
- data/vendor/git/graphy/lib/graphy/biconnected.rb +84 -0
- data/vendor/git/graphy/lib/graphy/chinese_postman.rb +91 -0
- data/vendor/git/graphy/lib/graphy/classes/graph_classes.rb +28 -0
- data/vendor/git/graphy/lib/graphy/common.rb +63 -0
- data/vendor/git/graphy/lib/graphy/comparability.rb +63 -0
- data/vendor/git/graphy/lib/graphy/directed_graph.rb +76 -0
- data/vendor/git/graphy/lib/graphy/directed_graph/algorithms.rb +92 -0
- data/vendor/git/graphy/lib/graphy/directed_graph/distance.rb +167 -0
- data/vendor/git/graphy/lib/graphy/dot.rb +94 -0
- data/vendor/git/graphy/lib/graphy/edge.rb +37 -0
- data/vendor/git/graphy/lib/graphy/ext.rb +79 -0
- data/vendor/git/graphy/lib/graphy/graph.rb +631 -0
- data/vendor/git/graphy/lib/graphy/graph_api.rb +35 -0
- data/vendor/git/graphy/lib/graphy/labels.rb +113 -0
- data/vendor/git/graphy/lib/graphy/maximum_flow.rb +77 -0
- data/vendor/git/graphy/lib/graphy/ruby_compatibility.rb +17 -0
- data/vendor/git/graphy/lib/graphy/search.rb +511 -0
- data/vendor/git/graphy/lib/graphy/strong_components.rb +93 -0
- data/vendor/git/graphy/lib/graphy/support/support.rb +9 -0
- data/vendor/git/graphy/lib/graphy/undirected_graph.rb +57 -0
- data/vendor/git/graphy/lib/graphy/undirected_graph/algorithms.rb +90 -0
- data/vendor/git/graphy/spec/biconnected_spec.rb +27 -0
- data/vendor/git/graphy/spec/chinese_postman_spec.rb +27 -0
- data/vendor/git/graphy/spec/community_spec.rb +44 -0
- data/vendor/git/graphy/spec/complement_spec.rb +27 -0
- data/vendor/git/graphy/spec/digraph_distance_spec.rb +121 -0
- data/vendor/git/graphy/spec/digraph_spec.rb +339 -0
- data/vendor/git/graphy/spec/dot_spec.rb +48 -0
- data/vendor/git/graphy/spec/edge_spec.rb +159 -0
- data/vendor/git/graphy/spec/inspection_spec.rb +40 -0
- data/vendor/git/graphy/spec/multi_edge_spec.rb +32 -0
- data/vendor/git/graphy/spec/neighborhood_spec.rb +38 -0
- data/vendor/git/graphy/spec/properties_spec.rb +146 -0
- data/vendor/git/graphy/spec/search_spec.rb +227 -0
- data/vendor/git/graphy/spec/spec.opts +4 -0
- data/vendor/git/graphy/spec/spec_helper.rb +56 -0
- data/vendor/git/graphy/spec/strong_components_spec.rb +61 -0
- data/vendor/git/graphy/spec/triangulated_spec.rb +125 -0
- data/vendor/git/graphy/spec/undirected_graph_spec.rb +220 -0
- data/vendor/git/graphy/vendor/priority-queue/CHANGELOG +33 -0
- data/vendor/git/graphy/vendor/priority-queue/Makefile +140 -0
- data/vendor/git/graphy/vendor/priority-queue/README +133 -0
- data/vendor/git/graphy/vendor/priority-queue/benchmark/dijkstra.rb +171 -0
- data/vendor/git/graphy/vendor/priority-queue/compare_comments.rb +49 -0
- data/vendor/git/graphy/vendor/priority-queue/doc/c-vs-rb.png +0 -0
- data/vendor/git/graphy/vendor/priority-queue/doc/compare_big.gp +14 -0
- data/vendor/git/graphy/vendor/priority-queue/doc/compare_big.png +0 -0
- data/vendor/git/graphy/vendor/priority-queue/doc/compare_small.gp +15 -0
- data/vendor/git/graphy/vendor/priority-queue/doc/compare_small.png +0 -0
- data/vendor/git/graphy/vendor/priority-queue/doc/results.csv +37 -0
- data/vendor/git/graphy/vendor/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
- data/vendor/git/graphy/vendor/priority-queue/ext/priority_queue/CPriorityQueue/priority_queue.c +947 -0
- data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue.rb +14 -0
- data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
- data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
- data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/ruby_priority_queue.rb +526 -0
- data/vendor/git/graphy/vendor/priority-queue/priority_queue.so +0 -0
- data/vendor/git/graphy/vendor/priority-queue/setup.rb +1551 -0
- data/vendor/git/graphy/vendor/priority-queue/test/priority_queue_test.rb +371 -0
- data/vendor/git/graphy/vendor/rdot.rb +360 -0
- metadata +83 -1
@@ -0,0 +1,93 @@
|
|
1
|
+
module Graphy
|
2
|
+
module StrongComponents
|
3
|
+
# strong_components computes the strongly connected components
|
4
|
+
# of a graph using Tarjan's algorithm based on DFS. See: Robert E. Tarjan
|
5
|
+
# _Depth_First_Search_and_Linear_Graph_Algorithms_. SIAM Journal on
|
6
|
+
# Computing, 1(2):146-160, 1972
|
7
|
+
#
|
8
|
+
# The output of the algorithm is an array of components where is
|
9
|
+
# component is an array of vertices
|
10
|
+
#
|
11
|
+
# A strongly connected component of a directed graph G=(V,E) is a maximal
|
12
|
+
# set of vertices U which is in V such that for every pair of
|
13
|
+
# vertices u and v in U, we have both a path from u to v
|
14
|
+
# and path from v to u. That is to say that u and v are reachable
|
15
|
+
# from each other.
|
16
|
+
#
|
17
|
+
def strong_components
|
18
|
+
dfs_num = 0
|
19
|
+
stack = []; result = []; root = {}; comp = {}; number = {}
|
20
|
+
|
21
|
+
# Enter vertex callback
|
22
|
+
enter = Proc.new do |v|
|
23
|
+
root[v] = v
|
24
|
+
comp[v] = :new
|
25
|
+
number[v] = (dfs_num += 1)
|
26
|
+
stack.push(v)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Exit vertex callback
|
30
|
+
exit = Proc.new do |v|
|
31
|
+
adjacent(v).each do |w|
|
32
|
+
if comp[w] == :new
|
33
|
+
root[v] = (number[root[v]] < number[root[w]] ? root[v] : root[w])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if root[v] == v
|
37
|
+
component = []
|
38
|
+
begin
|
39
|
+
w = stack.pop
|
40
|
+
comp[w] = :assigned
|
41
|
+
component << w
|
42
|
+
end until w == v
|
43
|
+
result << component
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Execute depth first search
|
48
|
+
dfs({:enter_vertex => enter, :exit_vertex => exit}); result
|
49
|
+
|
50
|
+
end # strong_components
|
51
|
+
|
52
|
+
# Returns a condensation graph of the strongly connected components
|
53
|
+
# Each node is an array of nodes from the original graph
|
54
|
+
def condensation
|
55
|
+
sc = strong_components
|
56
|
+
cg = DirectedMultiGraph.new
|
57
|
+
map = sc.inject({}) do |a,c|
|
58
|
+
c.each {|v| a[v] = c }; a
|
59
|
+
end
|
60
|
+
sc.each do |c|
|
61
|
+
c.each do |v|
|
62
|
+
adjacent(v).each {|v1| cg.add_edge!(c, map[v1]) unless cg.edge?(c, map[v1]) }
|
63
|
+
end
|
64
|
+
end;
|
65
|
+
cg
|
66
|
+
end
|
67
|
+
|
68
|
+
# Compute transitive closure of a graph. That is any node that is reachable
|
69
|
+
# along a path is added as a directed edge.
|
70
|
+
def transitive_closure!
|
71
|
+
cgtc = condensation.graphy_inner_transitive_closure!
|
72
|
+
cgtc.each do |cgv|
|
73
|
+
cgtc.adjacent(cgv).each do |adj|
|
74
|
+
cgv.each do |u|
|
75
|
+
adj.each {|v| add_edge!(u,v)}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end; self
|
79
|
+
end
|
80
|
+
|
81
|
+
# This returns the transitive closure of a graph. The original graph
|
82
|
+
# is not changed.
|
83
|
+
def transitive_closure() self.class.new(self).transitive_closure!; end
|
84
|
+
|
85
|
+
def graphy_inner_transitive_closure! # :nodoc:
|
86
|
+
sort.reverse.each do |u|
|
87
|
+
adjacent(u).each do |v|
|
88
|
+
adjacent(v).each {|w| add_edge!(u,w) unless edge?(u,w)}
|
89
|
+
end
|
90
|
+
end; self
|
91
|
+
end
|
92
|
+
end # StrongComponents
|
93
|
+
end # Graphy
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Graphy
|
2
|
+
|
3
|
+
module UndirectedGraphBuilder
|
4
|
+
|
5
|
+
autoload :Algorithms, "graphy/undirected_graph/algorithms"
|
6
|
+
|
7
|
+
include Graphy::GraphBuilder
|
8
|
+
extends_host
|
9
|
+
module ClassMethods
|
10
|
+
def [](*a)
|
11
|
+
self.new.from_array(*a)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*params)
|
16
|
+
args = (params.pop if params.last.kind_of? Hash) || {}
|
17
|
+
args[:algorithmic_category] = Graphy::UndirectedGraphBuilder::Algorithms
|
18
|
+
super *(params << args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This is a Digraph that allows for parallel edges, but does not
|
23
|
+
# allow loops
|
24
|
+
module UndirectedPseudoGraphBuilder
|
25
|
+
include UndirectedGraphBuilder
|
26
|
+
extends_host
|
27
|
+
module ClassMethods
|
28
|
+
def [](*a)
|
29
|
+
self.new.from_array(*a)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(*params)
|
34
|
+
args = (params.pop if params.last.kind_of? Hash) || {}
|
35
|
+
args[:parallel_edges] = true
|
36
|
+
super *(params << args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# This is a Digraph that allows for parallel edges and loops
|
41
|
+
module UndirectedMultiGraphBuilder
|
42
|
+
UndirectedPseudoGraphBuilder
|
43
|
+
extends_host
|
44
|
+
module ClassMethods
|
45
|
+
def [](*a)
|
46
|
+
self.new.from_array(*a)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(*params)
|
51
|
+
args = (params.pop if params.last.kind_of? Hash) || {}
|
52
|
+
args[:loops] = true
|
53
|
+
super *(params << args)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end # Graphy
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Graphy
|
2
|
+
module UndirectedGraphBuilder
|
3
|
+
module Algorithms
|
4
|
+
|
5
|
+
include Search
|
6
|
+
include Biconnected
|
7
|
+
include Comparability
|
8
|
+
|
9
|
+
# UndirectedGraph is by definition undirected, always returns false
|
10
|
+
def directed?() false; end
|
11
|
+
|
12
|
+
# Redefine degree (default was sum)
|
13
|
+
def degree(v) in_degree(v); end
|
14
|
+
|
15
|
+
# A vertex of an undirected graph is balanced by definition
|
16
|
+
def balanced?(v) true; end
|
17
|
+
|
18
|
+
# UndirectedGraph uses Edge for the edge class.
|
19
|
+
def edge_class() @parallel_edges ? Graphy::MultiEdge : Graphy::Edge; end
|
20
|
+
|
21
|
+
def remove_edge!(u, v=nil)
|
22
|
+
unless u.kind_of? Graphy::Arc
|
23
|
+
raise ArgumentError if @parallel_edges
|
24
|
+
u = edge_class[u,v]
|
25
|
+
end
|
26
|
+
super(u.reverse) unless u.source == u.target
|
27
|
+
super(u)
|
28
|
+
end
|
29
|
+
|
30
|
+
# A triangulated graph is an undirected perfect graph that every cycle of length greater than
|
31
|
+
# three possesses a chord. They have also been called chordal, rigid circuit, monotone transitive,
|
32
|
+
# and perfect elimination graphs.
|
33
|
+
#
|
34
|
+
# Implementation taken from Golumbic's, "Algorithmic Graph Theory and
|
35
|
+
# Perfect Graphs" pg. 90
|
36
|
+
def triangulated?
|
37
|
+
a = Hash.new {|h,k| h[k]=Set.new}; sigma=lexicograph_bfs
|
38
|
+
inv_sigma = sigma.inject({}) {|acc,val| acc[val] = sigma.index(val); acc}
|
39
|
+
sigma[0..-2].each do |v|
|
40
|
+
x = adjacent(v).select {|w| inv_sigma[v] < inv_sigma[w] }
|
41
|
+
unless x.empty?
|
42
|
+
u = sigma[x.map {|y| inv_sigma[y]}.min]
|
43
|
+
a[u].merge(x - [u])
|
44
|
+
end
|
45
|
+
return false unless a[v].all? {|z| adjacent?(v,z)}
|
46
|
+
end
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def chromatic_number
|
51
|
+
return triangulated_chromatic_number if triangulated?
|
52
|
+
raise NotImplementedError
|
53
|
+
end
|
54
|
+
|
55
|
+
# An interval graph can have its vertices into one-to-one
|
56
|
+
# correspondence with a set of intervals F of a linearly ordered
|
57
|
+
# set (like the real line) such that two vertices are connected
|
58
|
+
# by an edge of G if and only if their corresponding intervals
|
59
|
+
# have nonempty intersection.
|
60
|
+
def interval?() triangulated? and complement.comparability?; end
|
61
|
+
|
62
|
+
# A permutation diagram consists of n points on each of two parallel
|
63
|
+
# lines and n straight line segments matchin the points. The intersection
|
64
|
+
# graph of the line segments is called a permutation graph.
|
65
|
+
def permutation?() comparability? and complement.comparability?; end
|
66
|
+
|
67
|
+
# An undirected graph is defined to be split if there is a partition
|
68
|
+
# V = S + K of its vertex set into a stable set S and a complete set K.
|
69
|
+
def split?() triangulated? and complement.triangulated?; end
|
70
|
+
|
71
|
+
private
|
72
|
+
# Implementation taken from Golumbic's, "Algorithmic Graph Theory and
|
73
|
+
# Perfect Graphs" pg. 99
|
74
|
+
def triangulated_chromatic_number
|
75
|
+
chi = 1; s= Hash.new {|h,k| h[k]=0}
|
76
|
+
sigma=lexicograph_bfs
|
77
|
+
inv_sigma = sigma.inject({}) {|acc,val| acc[val] = sigma.index(val); acc}
|
78
|
+
sigma.each do |v|
|
79
|
+
x = adjacent(v).select {|w| inv_sigma[v] < inv_sigma[w] }
|
80
|
+
unless x.empty?
|
81
|
+
u = sigma[x.map {|y| inv_sigma[y]}.min]
|
82
|
+
s[u] = [s[u], x.size-1].max
|
83
|
+
chi = [chi, x.size+1].max if s[v] < x.size
|
84
|
+
end
|
85
|
+
end; chi
|
86
|
+
end
|
87
|
+
|
88
|
+
end # UndirectedGraphAlgorithms
|
89
|
+
end # UndirectedGraphBuilder
|
90
|
+
end # Graphy
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Biconnected" do # :nodoc:
|
4
|
+
describe "tarjan" do
|
5
|
+
it do
|
6
|
+
tarjan = UndirectedGraph[ 1, 2,
|
7
|
+
1, 5,
|
8
|
+
1, 6,
|
9
|
+
1, 7,
|
10
|
+
2, 3,
|
11
|
+
2, 4,
|
12
|
+
3, 4,
|
13
|
+
2, 5,
|
14
|
+
5, 6,
|
15
|
+
7, 8,
|
16
|
+
7, 9,
|
17
|
+
8, 9 ]
|
18
|
+
graphs, articulations = tarjan.biconnected
|
19
|
+
articulations.sort.should == [1,2,7]
|
20
|
+
graphs.size.should == 4
|
21
|
+
graphs.find {|g| g.size == 2}.vertices.sort.should == [1,7]
|
22
|
+
graphs.find {|g| g.size == 4}.vertices.sort.should == [1,2,5,6]
|
23
|
+
graphs.find {|g| g.size == 3 && g.vertex?(2)}.vertices.sort.should == [2,3,4]
|
24
|
+
graphs.find {|g| g.size == 3 && g.vertex?(7)}.vertices.sort.should == [7,8,9]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "ChinesePostman" do # :nodoc:
|
4
|
+
|
5
|
+
before do
|
6
|
+
@simple=Digraph[ 0,1, 0,2, 1,2, 1,3, 2,3, 3,0 ]
|
7
|
+
@weight = Proc.new {|e| 1}
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "closed_simple_tour" do
|
11
|
+
it do
|
12
|
+
tour = @simple.closed_chinese_postman_tour(0, @weight)
|
13
|
+
tour.size.should == 11
|
14
|
+
tour[0].should == 0
|
15
|
+
tour[10].should == 0
|
16
|
+
edges = Set.new
|
17
|
+
0.upto(9) do |n|
|
18
|
+
edges << Arc[tour[n],tour[n+1]]
|
19
|
+
@simple.edge?(tour[n],tour[n+1]).should be_true
|
20
|
+
end
|
21
|
+
edges.size.should == @simple.edges.size
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Community" do # :nodoc:
|
4
|
+
before do
|
5
|
+
@graph = Digraph[2,1, 3,1, 5,4, 6,5, 7,6, 7,2].add_vertex!(8)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "ancestors_must_return_ancestors" do
|
9
|
+
it do
|
10
|
+
@graph.ancestors(1).sort.should == [2,3,7]
|
11
|
+
@graph.ancestors(2).sort.should == [7]
|
12
|
+
@graph.ancestors(3).sort.should == []
|
13
|
+
@graph.ancestors(4).sort.should == [5,6,7]
|
14
|
+
@graph.ancestors(5).sort.should == [6,7]
|
15
|
+
@graph.ancestors(6).sort.should == [7]
|
16
|
+
@graph.ancestors(7).sort.should == []
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "descendants_must_return_descendants" do
|
21
|
+
it do
|
22
|
+
@graph.descendants(1).sort.should == []
|
23
|
+
@graph.descendants(2).sort.should == [1]
|
24
|
+
@graph.descendants(3).sort.should == [1]
|
25
|
+
@graph.descendants(4).sort.should == []
|
26
|
+
@graph.descendants(5).sort.should == [4]
|
27
|
+
@graph.descendants(6).sort.should == [4,5]
|
28
|
+
@graph.descendants(7).sort.should == [1,2,4,5,6]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "family_must_return_family" do
|
33
|
+
it do
|
34
|
+
@graph.family(1).sort.should == [2,3,4,5,6,7]
|
35
|
+
@graph.family(2).sort.should == [1,3,4,5,6,7]
|
36
|
+
@graph.family(3).sort.should == [1,2,4,5,6,7]
|
37
|
+
@graph.family(4).sort.should == [1,2,3,5,6,7]
|
38
|
+
@graph.family(5).sort.should == [1,2,3,4,6,7]
|
39
|
+
@graph.family(6).sort.should == [1,2,3,4,5,7]
|
40
|
+
@graph.family(7).sort.should == [1,2,3,4,5,6]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Complement" do # :nodoc:
|
4
|
+
|
5
|
+
describe "square" do
|
6
|
+
it do
|
7
|
+
x = UndirectedGraph[:a,:b, :b,:c, :c,:d, :d,:a].complement
|
8
|
+
x.edges.size.should == 2
|
9
|
+
x.edges.include?(Edge[:a,:c]).should be_true
|
10
|
+
x.edges.include?(Edge[:b,:d]).should be_true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "g1" do
|
15
|
+
it do
|
16
|
+
g1 = UndirectedGraph[ :a,:b, :a,:d, :a,:e, :a,:i, :a,:g, :a,:h,
|
17
|
+
:b,:c, :b,:f,
|
18
|
+
:c,:d, :c,:h,
|
19
|
+
:d,:h, :d,:e,
|
20
|
+
:e,:f,
|
21
|
+
:f,:g, :f,:h, :f,:i,
|
22
|
+
:h,:i ].complement
|
23
|
+
g1.edges.size.should == 19
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "DigraphDistance" do # :nodoc:
|
4
|
+
|
5
|
+
before do
|
6
|
+
@d = Digraph[ :a,:b, :a,:e,
|
7
|
+
:b,:c, :b,:e,
|
8
|
+
:c,:d,
|
9
|
+
:d,:c,
|
10
|
+
:e,:b, :e,:f,
|
11
|
+
:f,:c, :f,:d, :f,:e ]
|
12
|
+
|
13
|
+
@w = { Arc[:a,:b] => 9,
|
14
|
+
Arc[:a,:e] => 3,
|
15
|
+
Arc[:b,:c] => 2,
|
16
|
+
Arc[:b,:e] => 6,
|
17
|
+
Arc[:c,:d] => 1,
|
18
|
+
Arc[:d,:c] => 2,
|
19
|
+
Arc[:e,:b] => 2,
|
20
|
+
Arc[:e,:f] => 1,
|
21
|
+
Arc[:f,:c] => 2,
|
22
|
+
Arc[:f,:d] => 7,
|
23
|
+
Arc[:f,:e] => 2 }
|
24
|
+
@a = { :a => 0,
|
25
|
+
:b => 5,
|
26
|
+
:c => 6,
|
27
|
+
:d => 7,
|
28
|
+
:e => 3,
|
29
|
+
:f => 4 }
|
30
|
+
@simple_weight = Proc.new {|e| 1}
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "shortest_path" do
|
34
|
+
it do
|
35
|
+
x = Digraph[ :s,:u, :s,:w,
|
36
|
+
:j,:v,
|
37
|
+
:u,:j,
|
38
|
+
:v,:y,
|
39
|
+
:w,:u, :w,:v, :w,:y, :w,:x,
|
40
|
+
:x,:z ]
|
41
|
+
x.should be_acyclic
|
42
|
+
cost, path = x.shortest_path(:s,@simple_weight)
|
43
|
+
cost.should == {:x=>2, :v=>2, :y=>2, :w=>1, :s=>0, :z=>3, :u=>1, :j=> 2}
|
44
|
+
path.should == {:x=>:w, :v=>:w, :y=>:w, :w=>:s, :z=>:x, :u=>:s, :j=>:u}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "dijkstra_with_proc" do
|
49
|
+
it do
|
50
|
+
p = Proc.new {|e| @w[e]}
|
51
|
+
distance, path = @d.dijkstras_algorithm(:a,p)
|
52
|
+
distance.should == @a
|
53
|
+
path.should == { :d => :c, :c => :f, :f => :e, :b => :e, :e => :a}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "dijkstra_with_label" do
|
58
|
+
it do
|
59
|
+
@w.keys.each {|e| @d[e] = @w[e]}
|
60
|
+
@d.dijkstras_algorithm(:a)[0].should == @a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "dijkstra_with_bracket_label" do
|
65
|
+
it do
|
66
|
+
@w.keys.each do |e|
|
67
|
+
@d[e] = {:xyz => (@w[e])}
|
68
|
+
end
|
69
|
+
@d.dijkstras_algorithm(:a, :xyz)[0].should == @a
|
70
|
+
@w.keys.each do |e|
|
71
|
+
@d[e] = [@w[e]]
|
72
|
+
end
|
73
|
+
@d.dijkstras_algorithm(:a, 0)[0].should == @a
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "floyd_warshall" do
|
78
|
+
it do
|
79
|
+
simple = Digraph[ 0,1, 0,2, 1,2, 1,3, 2,3, 3,0 ]
|
80
|
+
|
81
|
+
cost, path, delta = simple.floyd_warshall(@simple_weight)
|
82
|
+
# Costs
|
83
|
+
cost[0].should == {0=>3, 1=>1, 2=>1, 3=>2}
|
84
|
+
cost[1].should == {0=>2, 1=>3, 2=>1, 3=>1}
|
85
|
+
cost[2].should == {0=>2, 1=>3, 2=>3, 3=>1}
|
86
|
+
cost[3].should == {0=>1, 1=>2, 2=>2, 3=>3}
|
87
|
+
|
88
|
+
# Paths
|
89
|
+
path[0].should == {0=>1, 1=>1, 2=>2, 3=>1}
|
90
|
+
path[1].should == {0=>3, 1=>3, 2=>2, 3=>3}
|
91
|
+
path[2].should == {0=>3, 1=>3, 2=>3, 3=>3}
|
92
|
+
path[3].should == {0=>0, 1=>0, 2=>0, 3=>0}
|
93
|
+
|
94
|
+
# Deltas
|
95
|
+
delta[0].should == 1
|
96
|
+
delta[1].should == 1
|
97
|
+
delta[2].should == -1
|
98
|
+
delta[3].should == -1
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "bellman_ford_moore" do
|
103
|
+
it do
|
104
|
+
fig24 = Digraph[ [:s,:e] => 8,
|
105
|
+
[:s,:d] => 4,
|
106
|
+
[:e,:c] => 2,
|
107
|
+
[:e,:d] => -5,
|
108
|
+
[:c,:b] => -2,
|
109
|
+
[:d,:c] => -2,
|
110
|
+
[:d,:a] => 4,
|
111
|
+
[:a,:c] => 10,
|
112
|
+
[:a,:b] => 9,
|
113
|
+
[:b,:c] => 5,
|
114
|
+
[:b,:a] => -3]
|
115
|
+
cost, path = fig24.bellman_ford_moore(:s)
|
116
|
+
cost.should == {:e=>8, :d=>3, :c=>1, :b=>-1, :a=>-4, :s=>0}
|
117
|
+
path.should == {:e=>:s, :d=>:e, :c=>:d, :b=>:c, :a=>:b}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|