graph_matching 0.1.0 → 0.1.1
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/CHANGELOG.md +6 -0
- data/graph_matching.gemspec +13 -11
- data/lib/graph_matching/version.rb +1 -1
- metadata +2 -77
- data/benchmark/mcm_bipartite/complete_bigraphs/benchmark.rb +0 -33
- data/benchmark/mcm_bipartite/complete_bigraphs/compare.gnuplot +0 -19
- data/benchmark/mcm_bipartite/complete_bigraphs/edges_times_vertexes.data +0 -500
- data/benchmark/mcm_bipartite/complete_bigraphs/plot.gnuplot +0 -21
- data/benchmark/mcm_bipartite/complete_bigraphs/plot.png +0 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/time.data +0 -499
- data/benchmark/mcm_general/complete_graphs/benchmark.rb +0 -30
- data/benchmark/mcm_general/complete_graphs/plot.gnuplot +0 -19
- data/benchmark/mcm_general/complete_graphs/plot.png +0 -0
- data/benchmark/mcm_general/complete_graphs/time.data +0 -499
- data/benchmark/mcm_general/complete_graphs/v_cubed.data +0 -500
- data/benchmark/mwm_bipartite/complete_bigraphs/benchmark.rb +0 -43
- data/benchmark/mwm_bipartite/complete_bigraphs/nmN.data +0 -499
- data/benchmark/mwm_bipartite/complete_bigraphs/nmN.xlsx +0 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/plot.gnuplot +0 -22
- data/benchmark/mwm_bipartite/complete_bigraphs/plot.png +0 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/time.data +0 -299
- data/benchmark/mwm_bipartite/misc/calc_d2/benchmark.rb +0 -25
- data/benchmark/mwm_general/complete_graphs/benchmark.rb +0 -32
- data/benchmark/mwm_general/complete_graphs/compare.gnuplot +0 -19
- data/benchmark/mwm_general/complete_graphs/mn_log_n.data +0 -299
- data/benchmark/mwm_general/complete_graphs/mn_log_n.xlsx +0 -0
- data/benchmark/mwm_general/complete_graphs/plot.gnuplot +0 -22
- data/benchmark/mwm_general/complete_graphs/plot.png +0 -0
- data/benchmark/mwm_general/complete_graphs/time.data +0 -299
- data/benchmark/mwm_general/incomplete_graphs/benchmark.rb +0 -38
- data/benchmark/mwm_general/incomplete_graphs/plot.gnuplot +0 -22
- data/benchmark/mwm_general/incomplete_graphs/plot.png +0 -0
- data/benchmark/mwm_general/incomplete_graphs/time_10_pct.data +0 -299
- data/benchmark/mwm_general/incomplete_graphs/time_20_pct.data +0 -299
- data/benchmark/mwm_general/incomplete_graphs/time_30_pct.data +0 -299
- data/profile/mcm_bipartite/compare.sh +0 -15
- data/profile/mcm_bipartite/publish.sh +0 -12
- data/profile/mwm_general/compare.sh +0 -15
- data/profile/mwm_general/profile.rb +0 -28
- data/profile/mwm_general/publish.sh +0 -12
- data/research/1965_edmonds.pdf +0 -0
- data/research/1975_even_kariv.pdf +0 -0
- data/research/1976_gabow.pdf +0 -0
- data/research/1980_micali_vazirani.pdf +0 -0
- data/research/1985_gabow.pdf +0 -0
- data/research/2002_tarjan.pdf +0 -0
- data/research/2013_zwick.pdf +0 -0
- data/research/examples/unweighted_general/1.txt +0 -86
- data/research/goodwin.pdf +0 -0
- data/research/kavathekar-scribe.pdf +0 -0
- data/research/kusner.pdf +0 -0
- data/research/van_rantwijk/mwm_example.py +0 -19
- data/research/van_rantwijk/mwmatching.py +0 -945
- data/spec/graph_matching/algorithm/matching_algorithm_spec.rb +0 -14
- data/spec/graph_matching/algorithm/mcm_bipartite_spec.rb +0 -98
- data/spec/graph_matching/algorithm/mcm_general_spec.rb +0 -159
- data/spec/graph_matching/algorithm/mwm_bipartite_spec.rb +0 -82
- data/spec/graph_matching/algorithm/mwm_general_spec.rb +0 -442
- data/spec/graph_matching/graph/bigraph_spec.rb +0 -73
- data/spec/graph_matching/graph/graph_spec.rb +0 -53
- data/spec/graph_matching/graph/weighted_spec.rb +0 -29
- data/spec/graph_matching/integer_vertexes_spec.rb +0 -21
- data/spec/graph_matching/matching_spec.rb +0 -89
- data/spec/graph_matching/visualize_spec.rb +0 -38
- data/spec/graph_matching_spec.rb +0 -9
- data/spec/spec_helper.rb +0 -26
@@ -1,14 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe GraphMatching::Algorithm::MatchingAlgorithm do
|
6
|
-
let(:algorithm) { described_class.new(double) }
|
7
|
-
|
8
|
-
describe '#assert' do
|
9
|
-
it 'returns an Assertion' do
|
10
|
-
expect(algorithm.assert('banana')).to \
|
11
|
-
be_a(GraphMatching::Assertion)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe GraphMatching::Algorithm::MCMBipartite do
|
6
|
-
let(:g) { GraphMatching::Graph::Bigraph.new }
|
7
|
-
|
8
|
-
describe '.new' do
|
9
|
-
it 'requires a Bigraph' do
|
10
|
-
expect { described_class.new('banana') }.to raise_error(TypeError)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#augment' do
|
15
|
-
it 'augments the matching' do
|
16
|
-
mcm = described_class.new(g)
|
17
|
-
m = [nil, nil, 3, 2]
|
18
|
-
m = mcm.send(:augment, m, [1, 2, 3, 4])
|
19
|
-
expect(m).to eq([nil, 2, 1, 4, 3])
|
20
|
-
m = mcm.send(:augment, m, [1, 2, 4, 5, 6, 7])
|
21
|
-
expect(m).to eq([nil, 2, 1, nil, 5, 4, 7, 6])
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe '#match' do
|
26
|
-
context 'empty graph' do
|
27
|
-
it 'returns empty set' do
|
28
|
-
m = described_class.new(g).match
|
29
|
-
expect(m).to be_empty
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'single vertex' do
|
34
|
-
it 'returns empty set' do
|
35
|
-
g.add_vertex(0)
|
36
|
-
expect(described_class.new(g).match).to be_empty
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'single edge' do
|
41
|
-
it 'returns set with one edge' do
|
42
|
-
e = [1, 2]
|
43
|
-
g.add_edge(*e)
|
44
|
-
m = described_class.new(g).match
|
45
|
-
expect(m.size).to eq(1)
|
46
|
-
expect(m.edge?(e)).to eq(true)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'complete bigraph with four vertexes' do
|
51
|
-
let(:edges) { [[1, 3], [1, 4], [2, 3], [2, 4]] }
|
52
|
-
|
53
|
-
it 'returns one of the two correct results' do
|
54
|
-
edges.each { |e| g.add_edge(*e) }
|
55
|
-
m = described_class.new(g).match
|
56
|
-
expect(m.size).to eq(2)
|
57
|
-
outcomes = [
|
58
|
-
RGL::AdjacencyGraph[1, 3, 2, 4],
|
59
|
-
RGL::AdjacencyGraph[1, 4, 2, 3]
|
60
|
-
]
|
61
|
-
reconstructed = RGL::AdjacencyGraph.new
|
62
|
-
m.to_a.each { |edge| reconstructed.add_edge(*edge) }
|
63
|
-
expect(outcomes).to include(reconstructed)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# The following example is by Derrick Stolee
|
68
|
-
# http://www.youtube.com/watch?v=C9c8zEZXboA
|
69
|
-
context 'incomplete bigraph with twelve vertexes' do
|
70
|
-
let(:edges) {
|
71
|
-
[
|
72
|
-
[1, 8],
|
73
|
-
[2, 9], [2, 10],
|
74
|
-
[3, 7], [3, 9], [3, 12],
|
75
|
-
[4, 8], [4, 10],
|
76
|
-
[5, 10], [5, 11],
|
77
|
-
[6, 11]
|
78
|
-
]
|
79
|
-
}
|
80
|
-
|
81
|
-
it 'returns one of the five correct results' do
|
82
|
-
edges.each { |e| g.add_edge(*e) }
|
83
|
-
m = described_class.new(g).match
|
84
|
-
expect(m.size).to eq(5)
|
85
|
-
outcomes = [
|
86
|
-
RGL::AdjacencyGraph[1, 8, 2, 9, 3, 7, 5, 10, 6, 11],
|
87
|
-
RGL::AdjacencyGraph[1, 8, 2, 9, 3, 7, 4, 10, 5, 11],
|
88
|
-
RGL::AdjacencyGraph[1, 8, 2, 9, 3, 7, 4, 10, 6, 11],
|
89
|
-
RGL::AdjacencyGraph[1, 8, 2, 9, 3, 12, 4, 10, 5, 11],
|
90
|
-
RGL::AdjacencyGraph[2, 9, 3, 7, 4, 8, 5, 10, 6, 11]
|
91
|
-
]
|
92
|
-
reconstructed = RGL::AdjacencyGraph.new
|
93
|
-
m.to_a.each { |edge| reconstructed.add_edge(*edge) }
|
94
|
-
expect(outcomes).to include(reconstructed)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,159 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe GraphMatching::Algorithm::MCMGeneral do
|
6
|
-
let(:graph_class) { GraphMatching::Graph::Graph }
|
7
|
-
let(:g) { graph_class.new }
|
8
|
-
|
9
|
-
describe '.new' do
|
10
|
-
it 'requires a Graph' do
|
11
|
-
expect { described_class.new('banana') }.to raise_error(TypeError)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe '#match' do
|
16
|
-
def complete_graph(n)
|
17
|
-
g = graph_class.new
|
18
|
-
1.upto(n - 1) do |i|
|
19
|
-
(i + 1).upto(n) do |j|
|
20
|
-
g.add_edge(i, j)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
g
|
24
|
-
end
|
25
|
-
|
26
|
-
context 'empty graph' do
|
27
|
-
it 'returns empty set' do
|
28
|
-
expect(described_class.new(g).match).to be_empty
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'single vertex' do
|
33
|
-
it 'returns empty set' do
|
34
|
-
g.add_vertex(1)
|
35
|
-
expect(described_class.new(g).match).to be_empty
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context 'two vertexes' do
|
40
|
-
let(:g) { graph_class[1, 2] }
|
41
|
-
|
42
|
-
it 'returns one edge' do
|
43
|
-
m = described_class.new(g).match
|
44
|
-
expect(m.size).to eq(1)
|
45
|
-
expect(m).to match_edges [[1, 2]]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'complete graph with four vertexes' do
|
50
|
-
it 'returns two disjoint edges' do
|
51
|
-
g = graph_class[
|
52
|
-
1, 2,
|
53
|
-
1, 3,
|
54
|
-
1, 4,
|
55
|
-
2, 3,
|
56
|
-
2, 4,
|
57
|
-
3, 4
|
58
|
-
]
|
59
|
-
m = described_class.new(g).match
|
60
|
-
expect(m.size).to eq(2)
|
61
|
-
expect(m.vertexes).to match_array([1, 2, 3, 4])
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'graph with stem (123) and blossom (456)' do
|
66
|
-
it 'returns an expected result' do
|
67
|
-
g = graph_class[
|
68
|
-
1, 2,
|
69
|
-
2, 3,
|
70
|
-
3, 4,
|
71
|
-
4, 5,
|
72
|
-
5, 6,
|
73
|
-
6, 4
|
74
|
-
]
|
75
|
-
m = described_class.new(g).match
|
76
|
-
expect(m.size).to eq(3)
|
77
|
-
expect(m).to match_edges [[1, 2], [3, 4], [5, 6]]
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# TODO: Other algorithms (e.g. both MWM) support disconnected
|
82
|
-
# graphs. MCM General should too.
|
83
|
-
context 'disconnected graph' do
|
84
|
-
it 'raises a DisconnectedGraph error' do
|
85
|
-
2.times { g.add_vertex(double) }
|
86
|
-
expect { described_class.new(g).match }.to \
|
87
|
-
raise_error(GraphMatching::DisconnectedGraph)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'simple example: graph with blossom (234)' do
|
92
|
-
g = graph_class[
|
93
|
-
1, 2,
|
94
|
-
2, 3,
|
95
|
-
2, 4,
|
96
|
-
3, 4,
|
97
|
-
4, 5,
|
98
|
-
5, 6
|
99
|
-
]
|
100
|
-
m = described_class.new(g).match
|
101
|
-
expect(m.size).to eq(3)
|
102
|
-
expect(m).to match_edges [[1, 2], [3, 4], [5, 6]]
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'example from West\'s Introduction to Graph Theory, p. 143' do
|
106
|
-
g = graph_class[
|
107
|
-
1, 2,
|
108
|
-
1, 8,
|
109
|
-
2, 3,
|
110
|
-
3, 4,
|
111
|
-
3, 7,
|
112
|
-
4, 5,
|
113
|
-
4, 7,
|
114
|
-
5, 6,
|
115
|
-
7, 9,
|
116
|
-
8, 9,
|
117
|
-
10, 8
|
118
|
-
]
|
119
|
-
m = described_class.new(g).match
|
120
|
-
expect(m.size).to eq(5)
|
121
|
-
expect(m).to match_edges [[1, 2], [3, 4], [5, 6], [7, 9], [8, 10]]
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'example from Gabow (1976)' do
|
125
|
-
g = graph_class[
|
126
|
-
1, 2,
|
127
|
-
2, 3,
|
128
|
-
1, 3,
|
129
|
-
1, 10,
|
130
|
-
3, 9,
|
131
|
-
3, 4,
|
132
|
-
4, 7,
|
133
|
-
4, 8,
|
134
|
-
7, 8,
|
135
|
-
9, 5,
|
136
|
-
5, 6,
|
137
|
-
6, 7
|
138
|
-
]
|
139
|
-
m = described_class.new(g).match
|
140
|
-
expect(m).to match_edges [[10, 1], [2, 3], [4, 8], [7, 6], [5, 9]]
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'various complete graphs' do
|
144
|
-
[
|
145
|
-
[1, 0], # size of graph, expected size of matching
|
146
|
-
[2, 1],
|
147
|
-
[3, 1],
|
148
|
-
[4, 2],
|
149
|
-
[5, 2],
|
150
|
-
[6, 3],
|
151
|
-
[20, 10]
|
152
|
-
].each do |test|
|
153
|
-
g = complete_graph(test[0])
|
154
|
-
m = described_class.new(g).match
|
155
|
-
expect(m.size).to eq(test[1])
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe GraphMatching::Algorithm::MWMBipartite do
|
6
|
-
let(:graph_class) { GraphMatching::Graph::WeightedBigraph }
|
7
|
-
|
8
|
-
describe '.new' do
|
9
|
-
it 'requires a WeightedBigraph' do
|
10
|
-
expect { described_class.new('banana') }.to raise_error(TypeError)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#match' do
|
15
|
-
context 'empty graph' do
|
16
|
-
it 'returns the expected matching' do
|
17
|
-
g = graph_class.new
|
18
|
-
m = described_class.new(g).match
|
19
|
-
expect(m.size).to eq(0)
|
20
|
-
expect(m.weight(g)).to eq(0)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context 'trivial bigraph with two vertexes' do
|
25
|
-
it 'returns the expected matching' do
|
26
|
-
g = graph_class[[1, 2, 7]]
|
27
|
-
m = described_class.new(g).match
|
28
|
-
expect(m.size).to eq(1)
|
29
|
-
expect(m).to match_edges [[1, 2]]
|
30
|
-
expect(m.weight(g)).to eq(7)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'complete bigraph with three vertexes' do
|
35
|
-
it 'returns the expected matching' do
|
36
|
-
g = graph_class[
|
37
|
-
[1, 2, 1],
|
38
|
-
[1, 3, 2]
|
39
|
-
]
|
40
|
-
m = described_class.new(g).match
|
41
|
-
expect(m).to match_edges [[1, 3]]
|
42
|
-
expect(m.weight(g)).to eq(2)
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'supports negative weights' do
|
46
|
-
g = graph_class[
|
47
|
-
[1, 2, -1],
|
48
|
-
[1, 3, -3]
|
49
|
-
]
|
50
|
-
m = described_class.new(g).match
|
51
|
-
expect(m).to match_edges [[1, 2]]
|
52
|
-
expect(m.weight(g)).to eq(-1)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context 'bigraph with two connected components' do
|
57
|
-
it 'returns one of two expected matchings' do
|
58
|
-
g = graph_class[
|
59
|
-
[1, 5, 3],
|
60
|
-
[2, 4, 2],
|
61
|
-
[2, 6, 2],
|
62
|
-
[3, 5, 3]
|
63
|
-
]
|
64
|
-
m = described_class.new(g).match
|
65
|
-
expect(m.size).to eq(2)
|
66
|
-
expect(m.weight(g)).to eq(5)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'returns the expected matching' do
|
70
|
-
g = graph_class[
|
71
|
-
[1, 5, 4],
|
72
|
-
[2, 4, 2],
|
73
|
-
[2, 6, 1],
|
74
|
-
[3, 5, 3]
|
75
|
-
]
|
76
|
-
m = described_class.new(g).match
|
77
|
-
expect(m).to match_edges [[1, 5], [2, 4]]
|
78
|
-
expect(m.weight(g)).to eq(6)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,442 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe GraphMatching::Algorithm::MWMGeneral do
|
6
|
-
let(:graph_class) { GraphMatching::Graph::WeightedGraph }
|
7
|
-
|
8
|
-
describe '.new' do
|
9
|
-
it 'requires a WeightedGraph' do
|
10
|
-
expect { described_class.new('banana') }.to raise_error(TypeError)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#blossom_leaves' do
|
15
|
-
context 'five vertexes, one blossom' do
|
16
|
-
it 'returns array of leaves' do
|
17
|
-
g = graph_class[
|
18
|
-
[0, 1, 0],
|
19
|
-
[1, 2, 0],
|
20
|
-
[1, 3, 0],
|
21
|
-
[2, 3, 0],
|
22
|
-
[3, 4, 0]
|
23
|
-
]
|
24
|
-
a = described_class.new(g)
|
25
|
-
a.instance_variable_set(
|
26
|
-
:@blossom_children,
|
27
|
-
[
|
28
|
-
nil,
|
29
|
-
nil,
|
30
|
-
nil,
|
31
|
-
nil,
|
32
|
-
nil,
|
33
|
-
[2, 3, 4]
|
34
|
-
]
|
35
|
-
)
|
36
|
-
expect(a.send(:blossom_leaves, 0)).to eq([0])
|
37
|
-
expect(a.send(:blossom_leaves, 4)).to eq([4])
|
38
|
-
expect(a.send(:blossom_leaves, 5)).to eq([2, 3, 4])
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe '#match' do
|
44
|
-
context 'empty graph' do
|
45
|
-
it 'returns empty matching' do
|
46
|
-
g = graph_class.new
|
47
|
-
m = described_class.new(g).match(true)
|
48
|
-
expect(m).to be_empty
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context 'single vertex' do
|
53
|
-
it 'returns empty matching' do
|
54
|
-
g = graph_class.new
|
55
|
-
g.add_vertex(0)
|
56
|
-
m = described_class.new(g).match(true)
|
57
|
-
expect(m).to be_empty
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context 'two vertexes, but no edge' do
|
62
|
-
it 'returns empty matching' do
|
63
|
-
g = graph_class.new
|
64
|
-
g.add_vertex(0)
|
65
|
-
g.add_vertex(1)
|
66
|
-
m = described_class.new(g).match(true)
|
67
|
-
expect(m).to be_empty
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'two vertexes' do
|
72
|
-
it 'returns matching of size 1' do
|
73
|
-
g = graph_class[[0, 1, 7]]
|
74
|
-
m = described_class.new(g).match(true)
|
75
|
-
expect(m).to match_edges [[0, 1]]
|
76
|
-
expect(m.weight(g)).to eq(7)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
context 'three vertexes' do
|
81
|
-
it 'matches the edge with greater weight' do
|
82
|
-
g = graph_class[
|
83
|
-
[0, 1, 1],
|
84
|
-
[1, 2, 2],
|
85
|
-
[2, 0, 3]
|
86
|
-
]
|
87
|
-
m = described_class.new(g).match(true)
|
88
|
-
expect(m).to match_edges [[0, 2]]
|
89
|
-
expect(m.weight(g)).to eq(3)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'greatest weight edge cannot be used in complete matching' do
|
94
|
-
it 'returns the complete matching with max. weight' do
|
95
|
-
# In the following graph, edge 1=3 has the greatest weight,
|
96
|
-
# but that edge cannot be used in a complete matching.
|
97
|
-
g = graph_class[
|
98
|
-
[0, 1, 2],
|
99
|
-
[1, 2, 0],
|
100
|
-
[1, 3, 6],
|
101
|
-
[2, 3, 4],
|
102
|
-
[3, 4, 2]
|
103
|
-
]
|
104
|
-
m = described_class.new(g).match(true)
|
105
|
-
expect(m).to match_edges [[0, 1], [2, 3]]
|
106
|
-
expect(m.weight(g)).to eq(6)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'passes Van Rantwijk test 12' do
|
111
|
-
g = graph_class[[1, 2, 10], [2, 3, 11]]
|
112
|
-
m = described_class.new(g).match(false)
|
113
|
-
expect(m).to match_edges [[2, 3]]
|
114
|
-
expect(m.weight(g)).to eq(11)
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'passes Van Rantwijk test 13' do
|
118
|
-
g = graph_class[
|
119
|
-
[1, 2, 5],
|
120
|
-
[2, 3, 11],
|
121
|
-
[3, 4, 5]
|
122
|
-
]
|
123
|
-
m = described_class.new(g).match(false)
|
124
|
-
expect(m).to match_edges [[2, 3]]
|
125
|
-
expect(m.weight(g)).to eq(11)
|
126
|
-
end
|
127
|
-
|
128
|
-
it 'passes Van Rantwijk test 14: max. cardinality' do
|
129
|
-
g = graph_class[
|
130
|
-
[1, 2, 5],
|
131
|
-
[2, 3, 11],
|
132
|
-
[3, 4, 5]
|
133
|
-
]
|
134
|
-
m = described_class.new(g).match(true)
|
135
|
-
expect(m).to match_edges [[1, 2], [3, 4]]
|
136
|
-
expect(m.weight(g)).to eq(10)
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'passes Van Rantwijk test 15: floating-point weights' do
|
140
|
-
g = graph_class[
|
141
|
-
[1, 2, Math::PI],
|
142
|
-
[2, 3, Math.exp(1)],
|
143
|
-
[1, 3, 3.0],
|
144
|
-
[1, 4, Math.sqrt(2.0)]
|
145
|
-
]
|
146
|
-
m = described_class.new(g).match(false)
|
147
|
-
expect(m).to match_edges [[1, 4], [2, 3]]
|
148
|
-
expect(m.weight(g)).to be_within(0.00001).of(Math.sqrt(2.0) + Math.exp(1))
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'passes Van Rantwijk test 16: negative weights' do
|
152
|
-
g = graph_class[
|
153
|
-
[1, 2, 2],
|
154
|
-
[1, 3, -2],
|
155
|
-
[2, 3, 1],
|
156
|
-
[2, 4, -1],
|
157
|
-
[3, 4, -6]
|
158
|
-
]
|
159
|
-
m = described_class.new(g).match(false)
|
160
|
-
expect(m).to match_edges [[1, 2]]
|
161
|
-
expect(m.weight(g)).to eq(2)
|
162
|
-
m = described_class.new(g).match(true)
|
163
|
-
expect(m).to match_edges [[1, 3], [2, 4]]
|
164
|
-
expect(m.weight(g)).to eq(-3)
|
165
|
-
end
|
166
|
-
|
167
|
-
context 'Van Rantwijk test 20: Uses S-blossom for augmentation' do
|
168
|
-
it 'passes test 20-A' do
|
169
|
-
g = graph_class[
|
170
|
-
[1, 2, 8],
|
171
|
-
[1, 3, 9],
|
172
|
-
[2, 3, 10],
|
173
|
-
[3, 4, 7]
|
174
|
-
]
|
175
|
-
m = described_class.new(g).match(false)
|
176
|
-
expect(m).to match_edges [[1, 2], [3, 4]]
|
177
|
-
expect(m.weight(g)).to eq(15)
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'passes test 20-B' do
|
181
|
-
g = graph_class[
|
182
|
-
[1, 2, 8],
|
183
|
-
[1, 3, 9],
|
184
|
-
[2, 3, 10],
|
185
|
-
[3, 4, 7],
|
186
|
-
[1, 6, 5],
|
187
|
-
[4, 5, 6]
|
188
|
-
]
|
189
|
-
m = described_class.new(g).match(false)
|
190
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 5]]
|
191
|
-
expect(m.weight(g)).to eq(21)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# Van Rantwijk test 21
|
196
|
-
context 'create S-blossom, relabel as T-blossom, use for augmentation' do
|
197
|
-
it 'passes test 21-A' do
|
198
|
-
g = graph_class[
|
199
|
-
[1, 2, 9],
|
200
|
-
[1, 3, 8],
|
201
|
-
[2, 3, 10],
|
202
|
-
[1, 4, 5],
|
203
|
-
[4, 5, 4],
|
204
|
-
[1, 6, 3]
|
205
|
-
]
|
206
|
-
m = described_class.new(g).match(false)
|
207
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 5]]
|
208
|
-
end
|
209
|
-
|
210
|
-
it 'passes test 21-B' do
|
211
|
-
g = graph_class[
|
212
|
-
[1, 2, 9],
|
213
|
-
[1, 3, 8],
|
214
|
-
[2, 3, 10],
|
215
|
-
[1, 4, 5],
|
216
|
-
[4, 5, 3],
|
217
|
-
[1, 6, 4]
|
218
|
-
]
|
219
|
-
m = described_class.new(g).match(false)
|
220
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 5]]
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'passes test 21-C' do
|
224
|
-
g = graph_class[
|
225
|
-
[1, 2, 9],
|
226
|
-
[1, 3, 8],
|
227
|
-
[2, 3, 10],
|
228
|
-
[1, 4, 5],
|
229
|
-
[4, 5, 3],
|
230
|
-
[3, 6, 4]
|
231
|
-
]
|
232
|
-
m = described_class.new(g).match(false)
|
233
|
-
expect(m).to match_edges [[1, 2], [3, 6], [4, 5]]
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
context 'Van Rantwijk test 22' do
|
238
|
-
it 'creates nested S-blossom, uses for augmentation' do
|
239
|
-
g = graph_class[
|
240
|
-
[1, 2, 9],
|
241
|
-
[1, 3, 9],
|
242
|
-
[2, 3, 10],
|
243
|
-
[2, 4, 8],
|
244
|
-
[3, 5, 8],
|
245
|
-
[4, 5, 10],
|
246
|
-
[5, 6, 6]
|
247
|
-
]
|
248
|
-
m = described_class.new(g).match(false)
|
249
|
-
expect(m).to match_edges [[1, 3], [2, 4], [5, 6]]
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
context 'Van Rantwijk test 23' do
|
254
|
-
it 'create S-blossom, relabel as S, include in nested S-blossom' do
|
255
|
-
g = graph_class[
|
256
|
-
[1, 2, 10],
|
257
|
-
[1, 7, 10],
|
258
|
-
[2, 3, 12],
|
259
|
-
[3, 4, 20],
|
260
|
-
[3, 5, 20],
|
261
|
-
[4, 5, 25],
|
262
|
-
[5, 6, 10],
|
263
|
-
[6, 7, 10],
|
264
|
-
[7, 8, 8]
|
265
|
-
]
|
266
|
-
m = described_class.new(g).match(false)
|
267
|
-
expect(m).to match_edges [[1, 2], [3, 4], [5, 6], [7, 8]]
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
context 'Van Rantwijk test 24' do
|
272
|
-
it 'create nested S-blossom, augment, expand recursively' do
|
273
|
-
g = graph_class[
|
274
|
-
[1, 2, 8],
|
275
|
-
[1, 3, 8],
|
276
|
-
[2, 3, 10],
|
277
|
-
[2, 4, 12],
|
278
|
-
[3, 5, 12],
|
279
|
-
[4, 5, 14],
|
280
|
-
[4, 6, 12],
|
281
|
-
[5, 7, 12],
|
282
|
-
[6, 7, 14],
|
283
|
-
[7, 8, 12]
|
284
|
-
]
|
285
|
-
m = described_class.new(g).match(false)
|
286
|
-
expect(m).to match_edges [[1, 2], [3, 5], [4, 6], [7, 8]]
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
context 'Van Rantwijk test 25' do
|
291
|
-
it 'create S-blossom, relabel as T, expand' do
|
292
|
-
g = graph_class[
|
293
|
-
[1, 2, 23],
|
294
|
-
[1, 5, 22],
|
295
|
-
[1, 6, 15],
|
296
|
-
[2, 3, 25],
|
297
|
-
[3, 4, 22],
|
298
|
-
[4, 5, 25],
|
299
|
-
[4, 8, 14],
|
300
|
-
[5, 7, 13]
|
301
|
-
]
|
302
|
-
m = described_class.new(g).match(false)
|
303
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 8], [5, 7]]
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
context 'Van Rantwijk test 26' do
|
308
|
-
it 'create nested S-blossom, relabel as T, expand' do
|
309
|
-
g = graph_class[
|
310
|
-
[1, 2, 19],
|
311
|
-
[1, 3, 20],
|
312
|
-
[1, 8, 8],
|
313
|
-
[2, 3, 25],
|
314
|
-
[2, 4, 18],
|
315
|
-
[3, 5, 18],
|
316
|
-
[4, 5, 13],
|
317
|
-
[4, 7, 7],
|
318
|
-
[5, 6, 7]
|
319
|
-
]
|
320
|
-
m = described_class.new(g).match(false)
|
321
|
-
expect(m).to match_edges [[1, 8], [2, 3], [4, 7], [5, 6]]
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
context 'Van Rantwijk test 30' do
|
326
|
-
it 'create blossom, relabel as T in more than one way, expand, augment' do
|
327
|
-
g = graph_class[
|
328
|
-
[1, 2, 45],
|
329
|
-
[1, 5, 45],
|
330
|
-
[2, 3, 50],
|
331
|
-
[3, 4, 45],
|
332
|
-
[4, 5, 50],
|
333
|
-
[1, 6, 30],
|
334
|
-
[3, 9, 35],
|
335
|
-
[4, 8, 35],
|
336
|
-
[5, 7, 26],
|
337
|
-
[9, 10, 5]
|
338
|
-
]
|
339
|
-
m = described_class.new(g).match(false)
|
340
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 8], [5, 7], [9, 10]]
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
context 'Van Rantwijk test 31' do
|
345
|
-
it 'similar to test 30, but slightly different' do
|
346
|
-
g = graph_class[
|
347
|
-
[1, 2, 45],
|
348
|
-
[1, 5, 45],
|
349
|
-
[2, 3, 50],
|
350
|
-
[3, 4, 45],
|
351
|
-
[4, 5, 50],
|
352
|
-
[1, 6, 30],
|
353
|
-
[3, 9, 35],
|
354
|
-
[4, 8, 26], # differs from test 30
|
355
|
-
[5, 7, 40], # differs from test 30
|
356
|
-
[9, 10, 5]
|
357
|
-
]
|
358
|
-
m = described_class.new(g).match(false)
|
359
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 8], [5, 7], [9, 10]]
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
context 'Van Rantwijk test 32' do
|
364
|
-
# create blossom, relabel as T, expand such that a new
|
365
|
-
# least-slack S-to-free edge is produced, augment
|
366
|
-
it 'see comment' do
|
367
|
-
g = graph_class[
|
368
|
-
[1, 2, 45],
|
369
|
-
[1, 5, 45],
|
370
|
-
[2, 3, 50],
|
371
|
-
[3, 4, 45],
|
372
|
-
[4, 5, 50],
|
373
|
-
[1, 6, 30],
|
374
|
-
[3, 9, 35],
|
375
|
-
[4, 8, 28],
|
376
|
-
[5, 7, 26],
|
377
|
-
[9, 10, 5]
|
378
|
-
]
|
379
|
-
m = described_class.new(g).match(false)
|
380
|
-
expect(m).to match_edges [[1, 6], [2, 3], [4, 8], [5, 7], [9, 10]]
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
context 'Van Rantwijk test 33' do
|
385
|
-
# create nested blossom, relabel as T in more than one way,
|
386
|
-
# expand outer blossom such that inner blossom ends up on
|
387
|
-
# an augmenting path
|
388
|
-
it 'see comment' do
|
389
|
-
g = graph_class[
|
390
|
-
[1, 2, 45],
|
391
|
-
[1, 7, 45],
|
392
|
-
[2, 3, 50],
|
393
|
-
[3, 4, 45],
|
394
|
-
[4, 5, 95],
|
395
|
-
[4, 6, 94],
|
396
|
-
[5, 6, 94],
|
397
|
-
[6, 7, 50],
|
398
|
-
[1, 8, 30],
|
399
|
-
[3, 11, 35],
|
400
|
-
[5, 9, 36],
|
401
|
-
[7, 10, 26],
|
402
|
-
[11, 12, 5]
|
403
|
-
]
|
404
|
-
m = described_class.new(g).match(false)
|
405
|
-
expect(m).to match_edges [
|
406
|
-
[1, 8],
|
407
|
-
[2, 3],
|
408
|
-
[4, 6],
|
409
|
-
[5, 9],
|
410
|
-
[7, 10],
|
411
|
-
[11, 12]
|
412
|
-
]
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
context 'Van Rantwijk test 34: nest, relabel, expand' do
|
417
|
-
it 'create nested S-blossom, relabel as S, expand recursively' do
|
418
|
-
g = graph_class[
|
419
|
-
[1, 2, 40],
|
420
|
-
[1, 3, 40],
|
421
|
-
[2, 3, 60],
|
422
|
-
[2, 4, 55],
|
423
|
-
[3, 5, 55],
|
424
|
-
[4, 5, 50],
|
425
|
-
[1, 8, 15],
|
426
|
-
[5, 7, 30],
|
427
|
-
[7, 6, 10],
|
428
|
-
[8, 10, 10],
|
429
|
-
[4, 9, 30]
|
430
|
-
]
|
431
|
-
m = described_class.new(g).match(false)
|
432
|
-
expect(m).to match_edges [
|
433
|
-
[1, 2],
|
434
|
-
[3, 5],
|
435
|
-
[4, 9],
|
436
|
-
[6, 7],
|
437
|
-
[8, 10]
|
438
|
-
]
|
439
|
-
end
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|