graph_matching 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +112 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +205 -0
- data/Rakefile +9 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/benchmark.rb +33 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/compare.gnuplot +19 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/edges_times_vertexes.data +500 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/plot.gnuplot +21 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/plot.png +0 -0
- data/benchmark/mcm_bipartite/complete_bigraphs/time.data +499 -0
- data/benchmark/mcm_general/complete_graphs/benchmark.rb +30 -0
- data/benchmark/mcm_general/complete_graphs/plot.gnuplot +19 -0
- data/benchmark/mcm_general/complete_graphs/plot.png +0 -0
- data/benchmark/mcm_general/complete_graphs/time.data +499 -0
- data/benchmark/mcm_general/complete_graphs/v_cubed.data +500 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/benchmark.rb +43 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/nmN.data +499 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/nmN.xlsx +0 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/plot.gnuplot +22 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/plot.png +0 -0
- data/benchmark/mwm_bipartite/complete_bigraphs/time.data +299 -0
- data/benchmark/mwm_bipartite/misc/calc_d2/benchmark.rb +29 -0
- data/benchmark/mwm_general/complete_graphs/benchmark.rb +32 -0
- data/benchmark/mwm_general/complete_graphs/compare.gnuplot +19 -0
- data/benchmark/mwm_general/complete_graphs/mn_log_n.data +299 -0
- data/benchmark/mwm_general/complete_graphs/mn_log_n.xlsx +0 -0
- data/benchmark/mwm_general/complete_graphs/plot.gnuplot +22 -0
- data/benchmark/mwm_general/complete_graphs/plot.png +0 -0
- data/benchmark/mwm_general/complete_graphs/time.data +299 -0
- data/benchmark/mwm_general/incomplete_graphs/benchmark.rb +39 -0
- data/benchmark/mwm_general/incomplete_graphs/plot.gnuplot +22 -0
- data/benchmark/mwm_general/incomplete_graphs/plot.png +0 -0
- data/benchmark/mwm_general/incomplete_graphs/time_10_pct.data +299 -0
- data/benchmark/mwm_general/incomplete_graphs/time_20_pct.data +299 -0
- data/benchmark/mwm_general/incomplete_graphs/time_30_pct.data +299 -0
- data/graph_matching.gemspec +35 -0
- data/lib/graph_matching.rb +15 -0
- data/lib/graph_matching/algorithm/matching_algorithm.rb +23 -0
- data/lib/graph_matching/algorithm/mcm_bipartite.rb +118 -0
- data/lib/graph_matching/algorithm/mcm_general.rb +289 -0
- data/lib/graph_matching/algorithm/mwm_bipartite.rb +147 -0
- data/lib/graph_matching/algorithm/mwm_general.rb +1086 -0
- data/lib/graph_matching/algorithm/mwmg_delta_assertions.rb +94 -0
- data/lib/graph_matching/assertion.rb +41 -0
- data/lib/graph_matching/core_ext/set.rb +36 -0
- data/lib/graph_matching/directed_edge_set.rb +31 -0
- data/lib/graph_matching/errors.rb +23 -0
- data/lib/graph_matching/graph/bigraph.rb +37 -0
- data/lib/graph_matching/graph/graph.rb +63 -0
- data/lib/graph_matching/graph/weighted.rb +112 -0
- data/lib/graph_matching/graph/weighted_bigraph.rb +17 -0
- data/lib/graph_matching/graph/weighted_graph.rb +17 -0
- data/lib/graph_matching/integer_vertexes.rb +29 -0
- data/lib/graph_matching/matching.rb +120 -0
- data/lib/graph_matching/ordered_set.rb +59 -0
- data/lib/graph_matching/version.rb +6 -0
- data/lib/graph_matching/visualize.rb +93 -0
- data/profile/mcm_bipartite/compare.sh +15 -0
- data/profile/mcm_bipartite/publish.sh +12 -0
- data/profile/mwm_general/compare.sh +15 -0
- data/profile/mwm_general/profile.rb +28 -0
- data/profile/mwm_general/publish.sh +12 -0
- 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 +86 -0
- 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 +19 -0
- data/research/van_rantwijk/mwmatching.py +945 -0
- data/spec/graph_matching/algorithm/matching_algorithm_spec.rb +14 -0
- data/spec/graph_matching/algorithm/mcm_bipartite_spec.rb +98 -0
- data/spec/graph_matching/algorithm/mcm_general_spec.rb +159 -0
- data/spec/graph_matching/algorithm/mwm_bipartite_spec.rb +82 -0
- data/spec/graph_matching/algorithm/mwm_general_spec.rb +439 -0
- data/spec/graph_matching/graph/bigraph_spec.rb +73 -0
- data/spec/graph_matching/graph/graph_spec.rb +53 -0
- data/spec/graph_matching/graph/weighted_spec.rb +29 -0
- data/spec/graph_matching/integer_vertexes_spec.rb +21 -0
- data/spec/graph_matching/matching_spec.rb +89 -0
- data/spec/graph_matching/visualize_spec.rb +38 -0
- data/spec/graph_matching_spec.rb +9 -0
- data/spec/spec_helper.rb +26 -0
- metadata +263 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative 'weighted'
|
4
|
+
require_relative '../algorithm/mwm_general'
|
5
|
+
|
6
|
+
module GraphMatching
|
7
|
+
module Graph
|
8
|
+
# A graph whose edges have weights. See `Weighted`.
|
9
|
+
class WeightedGraph < Graph
|
10
|
+
include Weighted
|
11
|
+
|
12
|
+
def maximum_weighted_matching(max_cardinality)
|
13
|
+
Algorithm::MWMGeneral.new(self).match(max_cardinality)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GraphMatching
|
4
|
+
# Converts the vertices of a graph to integers. Many graph
|
5
|
+
# matching algorithms require integer vertexes.
|
6
|
+
module IntegerVertexes
|
7
|
+
# Converts the vertices of `graph` to positive nonzero integers.
|
8
|
+
# For example, given a graph (a=b), returns a new graph (1=2).
|
9
|
+
# It also returns a legend, which maps the integers to the
|
10
|
+
# original vertexes.
|
11
|
+
#
|
12
|
+
def self.to_integers(graph)
|
13
|
+
fail ArgumentError unless graph.is_a?(RGL::MutableGraph)
|
14
|
+
legend = {}
|
15
|
+
reverse_legend = {}
|
16
|
+
new_graph = graph.class.new
|
17
|
+
graph.vertices.each_with_index do |vertex, ix|
|
18
|
+
legend[ix + 1] = vertex
|
19
|
+
reverse_legend[vertex] = ix + 1
|
20
|
+
end
|
21
|
+
graph.edges.each do |edge|
|
22
|
+
source = reverse_legend[edge.source]
|
23
|
+
target = reverse_legend[edge.target]
|
24
|
+
new_graph.add_edge(source, target)
|
25
|
+
end
|
26
|
+
return new_graph, legend
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GraphMatching
|
4
|
+
# > In .. graph theory, a matching .. in a graph is a set of
|
5
|
+
# > edges without common vertices.
|
6
|
+
# > https://en.wikipedia.org/wiki/Matching_%28graph_theory%29
|
7
|
+
class Matching
|
8
|
+
# Gabow (1976) uses a simple array to store his matching. It
|
9
|
+
# has one element for each vertex in the graph. The value of
|
10
|
+
# each element is either the number of another vertex (Gabow
|
11
|
+
# uses sequential integers for vertex numbering) or a zero if
|
12
|
+
# unmatched. So, `.gabow` returns a `Matching` initialized
|
13
|
+
# from such an array.
|
14
|
+
def self.gabow(mate)
|
15
|
+
m = new
|
16
|
+
mate.each_with_index do |n1, ix|
|
17
|
+
next if n1.nil? || n1 == 0
|
18
|
+
n2 = mate[n1]
|
19
|
+
if n2 == ix
|
20
|
+
m.add([n1, n2])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
m
|
24
|
+
end
|
25
|
+
|
26
|
+
# Van Rantwijk's matching is constructed from two arrays,
|
27
|
+
# `mate` and `endpoint`.
|
28
|
+
#
|
29
|
+
# - `endpoint` is an array where each edge is represented by
|
30
|
+
# two consecutive elements, which are vertex numbers.
|
31
|
+
# - `mate` is an array whose indexes are vertex numbers, and
|
32
|
+
# whose values are `endpoint` indexes, or `nil` if the vertex
|
33
|
+
# is single (unmatched).
|
34
|
+
#
|
35
|
+
# A matched vertex `v`'s partner is `endpoint[mate[v]]`.
|
36
|
+
#
|
37
|
+
def self.from_endpoints(endpoint, mate)
|
38
|
+
m = Matching.new
|
39
|
+
mate.each do |p|
|
40
|
+
m.add([endpoint[p], endpoint[p ^ 1]]) unless p.nil?
|
41
|
+
end
|
42
|
+
m
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.[](*edges)
|
46
|
+
new.tap { |m| edges.each { |e| m.add(e) } }
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
@ary = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def [](i)
|
54
|
+
@ary[i]
|
55
|
+
end
|
56
|
+
|
57
|
+
def add(e)
|
58
|
+
i, j = e
|
59
|
+
@ary[i] = j
|
60
|
+
@ary[j] = i
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete(e)
|
64
|
+
i, j = e
|
65
|
+
@ary[i] = nil
|
66
|
+
@ary[j] = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# `edges` returns an array of undirected edges, represented as
|
70
|
+
# two-element arrays.
|
71
|
+
def edges
|
72
|
+
undirected_edges.map(&:to_a)
|
73
|
+
end
|
74
|
+
|
75
|
+
def empty?
|
76
|
+
@ary.all?(&:nil?)
|
77
|
+
end
|
78
|
+
|
79
|
+
def edge?(e)
|
80
|
+
i, j = e
|
81
|
+
!@ary[i].nil? && @ary[i] == j && @ary[j] == i
|
82
|
+
end
|
83
|
+
|
84
|
+
def vertex?(v)
|
85
|
+
@ary.include?(v)
|
86
|
+
end
|
87
|
+
|
88
|
+
# `size` returns number of edges
|
89
|
+
def size
|
90
|
+
@ary.compact.size / 2
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_a
|
94
|
+
result = []
|
95
|
+
skip = []
|
96
|
+
@ary.each_with_index { |e, i|
|
97
|
+
unless e.nil? || skip.include?(i)
|
98
|
+
result << [i, e]
|
99
|
+
skip << e
|
100
|
+
end
|
101
|
+
}
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
# Given a `Weighted` graph `g`, returns the sum of edge weights.
|
106
|
+
def weight(g)
|
107
|
+
edges.map { |e| g.w(e) }.reduce(0, :+)
|
108
|
+
end
|
109
|
+
|
110
|
+
def undirected_edges
|
111
|
+
@ary.each_with_index.inject(Set.new) { |set, (el, ix)|
|
112
|
+
el.nil? ? set : set.add(RGL::Edge::UnDirectedEdge.new(el, ix))
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def vertexes
|
117
|
+
@ary.compact
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module GraphMatching
|
4
|
+
# An `OrderedSet` acts like a `Set`, but preserves insertion order.
|
5
|
+
# Internally, a `Hash` is used because, as of Ruby 1.9, it
|
6
|
+
# preserves insertion order. The Set library happens to be built
|
7
|
+
# upon a Hash currently but this might change in the future.
|
8
|
+
class OrderedSet
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
# `.[]` returns a new ordered set containing the given objects.
|
12
|
+
# This mimics the signature of `Set.[]` and `Array.[]`.
|
13
|
+
def self.[](*args)
|
14
|
+
new.merge(args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@hash = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
# `add` `o` unless it already exists, preserving inserting order.
|
22
|
+
# This mimics the signature of `Set#add`. See alias `#enq`.
|
23
|
+
def add(o)
|
24
|
+
@hash[o] = true
|
25
|
+
end
|
26
|
+
alias_method :enq, :add
|
27
|
+
|
28
|
+
def deq
|
29
|
+
@hash.keys.first.tap do |k| @hash.delete(k) end
|
30
|
+
end
|
31
|
+
|
32
|
+
def each
|
33
|
+
@hash.each do |k, _v| yield k end
|
34
|
+
end
|
35
|
+
|
36
|
+
def empty?
|
37
|
+
@hash.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
# `merge` the elements of the given enumerable object to the set
|
41
|
+
# and returns self. This mimics the signature of `Set#merge`.
|
42
|
+
def merge(enum)
|
43
|
+
enum.each do |e| add(e) end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
# Removes the last element and returns it, or nil if empty.
|
48
|
+
# This mimics `Array#pop`. See related `#deq`.
|
49
|
+
def pop
|
50
|
+
@hash.keys.last.tap do |k| @hash.delete(k) end
|
51
|
+
end
|
52
|
+
|
53
|
+
# `push` appends the given object(s) and returns self. This
|
54
|
+
# mimics the signature of `Array#push`.
|
55
|
+
def push(*args)
|
56
|
+
merge(args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require 'rgl/rdot'
|
5
|
+
|
6
|
+
module GraphMatching
|
7
|
+
# Renders `GraphMatching::Graph` objects using `graphviz`.
|
8
|
+
class Visualize
|
9
|
+
TMP_DIR = '/tmp/graph_matching'
|
10
|
+
USR_BIN_ENV = '/usr/bin/env'
|
11
|
+
|
12
|
+
attr_reader :graph
|
13
|
+
|
14
|
+
def initialize(graph)
|
15
|
+
@graph = graph
|
16
|
+
end
|
17
|
+
|
18
|
+
# `dot` returns a string representing the graph, in .dot format.
|
19
|
+
# http://www.graphviz.org/content/dot-language
|
20
|
+
def dot
|
21
|
+
RGL::DOT::Graph.new('elements' => dot_edges).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
# `png` writes a ".png" file with graphviz and opens it
|
25
|
+
def png(base_filename)
|
26
|
+
check_that_dot_is_installed
|
27
|
+
mk_tmp_dir
|
28
|
+
abs_path = "#{TMP_DIR}/#{base_filename}.png"
|
29
|
+
write_png(abs_path)
|
30
|
+
system "open #{abs_path}"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_that_dot_is_installed
|
36
|
+
return if dot_installed?
|
37
|
+
$stderr.puts "Executable not found: dot"
|
38
|
+
$stderr.puts "Please install graphviz"
|
39
|
+
exit(1)
|
40
|
+
end
|
41
|
+
|
42
|
+
def dot_edge(u, v, label)
|
43
|
+
RGL::DOT::Edge.new(
|
44
|
+
{ 'from' => u, 'to' => v, 'label' => label },
|
45
|
+
['label']
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def dot_edges
|
50
|
+
graph.edges.map { |e| dot_edge(e.source, e.target, dot_edge_label(e)) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def dot_edge_label(edge)
|
54
|
+
graph.is_a?(GraphMatching::Graph::Weighted) ? graph.w([*edge]) : nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def assert_usr_bin_env_exists
|
58
|
+
return if File.exist?(USR_BIN_ENV)
|
59
|
+
$stderr.puts "File not found: #{USR_BIN_ENV}"
|
60
|
+
exit(1)
|
61
|
+
end
|
62
|
+
|
63
|
+
# `dot_installed?` returns true if `dot` is installed, otherwise
|
64
|
+
# false. Note that `system` returns true if the command gives
|
65
|
+
# zero exit status, false for non-zero exit status.
|
66
|
+
def dot_installed?
|
67
|
+
assert_usr_bin_env_exists
|
68
|
+
system "#{USR_BIN_ENV} which dot > /dev/null"
|
69
|
+
end
|
70
|
+
|
71
|
+
def mk_tmp_dir
|
72
|
+
Dir.mkdir(TMP_DIR) unless Dir.exist?(TMP_DIR)
|
73
|
+
end
|
74
|
+
|
75
|
+
def safe_vertex(v)
|
76
|
+
if v.is_a?(Integer)
|
77
|
+
v
|
78
|
+
elsif v.respond_to?(:to_dot)
|
79
|
+
v.to_dot
|
80
|
+
else
|
81
|
+
v.to_s.gsub(/[^a-zA-Z0-9]/, '')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def write_png(abs_path)
|
86
|
+
_so, se, st = Open3.capture3("dot -T png > #{abs_path}", stdin_data: dot)
|
87
|
+
return if st.success?
|
88
|
+
$stderr.puts "Failed to generate .png"
|
89
|
+
$stderr.puts se
|
90
|
+
exit(1)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
BENCHMARK_DIR='benchmark/mcm_bipartite/complete_bigraphs'
|
4
|
+
|
5
|
+
if [ ! -d "$BENCHMARK_DIR" ]; then
|
6
|
+
echo "Directory not found: $BENCHMARK_DIR" 1>&2
|
7
|
+
exit 1
|
8
|
+
fi
|
9
|
+
|
10
|
+
echo "Benchmarking .."
|
11
|
+
ruby -I lib "$BENCHMARK_DIR/benchmark.rb" > "$BENCHMARK_DIR/time2.data"
|
12
|
+
|
13
|
+
echo "Plotting .."
|
14
|
+
gnuplot "$BENCHMARK_DIR/compare.gnuplot"
|
15
|
+
open "$BENCHMARK_DIR/plot_compare.png"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
BENCHMARK_DIR='benchmark/mcm_bipartite/complete_bigraphs'
|
4
|
+
|
5
|
+
if [ ! -d "$BENCHMARK_DIR" ]; then
|
6
|
+
echo "Directory not found: $BENCHMARK_DIR" 1>&2
|
7
|
+
exit 1
|
8
|
+
fi
|
9
|
+
|
10
|
+
rm "$BENCHMARK_DIR/plot_compare.png"
|
11
|
+
mv "$BENCHMARK_DIR/time2.data" "$BENCHMARK_DIR/time.data"
|
12
|
+
gnuplot "$BENCHMARK_DIR/plot.gnuplot"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
BENCHMARK_DIR='benchmark/mwm_general/complete_graphs'
|
4
|
+
|
5
|
+
if [ ! -d "$BENCHMARK_DIR" ]; then
|
6
|
+
echo "Directory not found: $BENCHMARK_DIR" 1>&2
|
7
|
+
exit 1
|
8
|
+
fi
|
9
|
+
|
10
|
+
echo "Benchmarking .."
|
11
|
+
ruby -I lib "$BENCHMARK_DIR/benchmark.rb" > "$BENCHMARK_DIR/time2.data"
|
12
|
+
|
13
|
+
echo "Plotting .."
|
14
|
+
gnuplot "$BENCHMARK_DIR/compare.gnuplot"
|
15
|
+
open "$BENCHMARK_DIR/plot_compare.png"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# No shebang here. Run with:
|
2
|
+
#
|
3
|
+
# ruby -I lib profile/mwm_general/profile.rb
|
4
|
+
|
5
|
+
require 'graph_matching'
|
6
|
+
require 'ruby-prof'
|
7
|
+
|
8
|
+
def complete_graph(n)
|
9
|
+
g = GraphMatching::Graph::WeightedGraph.new
|
10
|
+
n_edges = (1 .. n - 1).reduce(:+)
|
11
|
+
0.upto(n - 2) do |i|
|
12
|
+
(i + 1).upto(n - 1) do |j|
|
13
|
+
g.add_edge(i, j)
|
14
|
+
g.set_w([i, j], rand(n_edges))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
g
|
18
|
+
end
|
19
|
+
|
20
|
+
g = complete_graph(100)
|
21
|
+
GC.disable
|
22
|
+
RubyProf.start
|
23
|
+
g.maximum_weighted_matching(true)
|
24
|
+
result = RubyProf.stop
|
25
|
+
GC.enable
|
26
|
+
|
27
|
+
printer = RubyProf::FlatPrinter.new(result)
|
28
|
+
printer.print(STDOUT)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
BENCHMARK_DIR='benchmark/mwm_general/complete_graphs'
|
4
|
+
|
5
|
+
if [ ! -d "$BENCHMARK_DIR" ]; then
|
6
|
+
echo "Directory not found: $BENCHMARK_DIR" 1>&2
|
7
|
+
exit 1
|
8
|
+
fi
|
9
|
+
|
10
|
+
rm "$BENCHMARK_DIR/plot_compare.png"
|
11
|
+
mv "$BENCHMARK_DIR/time2.data" "$BENCHMARK_DIR/time.data"
|
12
|
+
gnuplot "$BENCHMARK_DIR/plot.gnuplot"
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,86 @@
|
|
1
|
+
Stage 1
|
2
|
+
|
3
|
+
5 -- 7
|
4
|
+
/ || ||
|
5
|
+
1 = 3 || o
|
6
|
+
/ \ ||
|
7
|
+
r 6
|
8
|
+
\ /
|
9
|
+
2 = 4
|
10
|
+
/
|
11
|
+
a
|
12
|
+
|
13
|
+
S = [ 1 by r, 2 by r, 5 by 3, 6 by 3 ]
|
14
|
+
T = [ 3 by 1, 4 by 1 ]
|
15
|
+
|
16
|
+
Stage 2
|
17
|
+
|
18
|
+
1 = B -- 7
|
19
|
+
/ | ||
|
20
|
+
r | o
|
21
|
+
\ |
|
22
|
+
2 = 4
|
23
|
+
/
|
24
|
+
a
|
25
|
+
|
26
|
+
S = [ 1 by r, 2 by r, 5 by 3, 6 by 3 ]
|
27
|
+
T = [ 3 by 1, 4 by 1 ]
|
28
|
+
|
29
|
+
Stage 3
|
30
|
+
|
31
|
+
B -- 7
|
32
|
+
/ ||
|
33
|
+
a o
|
34
|
+
|
35
|
+
Find augmenting path from r, *through B* to a
|
36
|
+
|
37
|
+
1. AP = (a,B)
|
38
|
+
1. expand B
|
39
|
+
|
40
|
+
1 = B -- 7
|
41
|
+
/ | ||
|
42
|
+
r | o
|
43
|
+
\ |
|
44
|
+
2 = 4
|
45
|
+
/
|
46
|
+
a
|
47
|
+
|
48
|
+
1. Kusner says: "propagating the augmenting path through the expansion steps"
|
49
|
+
1. AP = (a,2), etc.. but how to find "etc"? We know we want an
|
50
|
+
alternating path, so starting at 2, find a matched edge.
|
51
|
+
1. AP = a2, 24
|
52
|
+
1. AP = a2, 24, 4B
|
53
|
+
1. B is a blossom. Expand it.
|
54
|
+
|
55
|
+
5 -- 7
|
56
|
+
/ || ||
|
57
|
+
1 = 3 || o
|
58
|
+
/ \ ||
|
59
|
+
r 6
|
60
|
+
\ /
|
61
|
+
2 = 4
|
62
|
+
/
|
63
|
+
a
|
64
|
+
|
65
|
+
1. AP = a2, 24, 46
|
66
|
+
1. AP = a2, 24, 46, 65
|
67
|
+
1. Should we follow (5,3) or (5,7), or both?
|
68
|
+
1. Following (5,7) doesn't reach r, and if we follow it,
|
69
|
+
either depth-first or breadth-first, we'll learn that.
|
70
|
+
1. AP = a2, 24, 46, 65, 53
|
71
|
+
1. AP = a2, 24, 46, 65, 53, 31
|
72
|
+
1. AP = a2, 24, 46, 65, 53, 31, 1r
|
73
|
+
1. Augmenting path: a, 2, 4, 6, 5, 3, 1, r
|
74
|
+
|
75
|
+
5 -- 7
|
76
|
+
//| ||
|
77
|
+
1 - 3 | o
|
78
|
+
// \|
|
79
|
+
r 6
|
80
|
+
\ //
|
81
|
+
2 - 4
|
82
|
+
//
|
83
|
+
a
|
84
|
+
|
85
|
+
1. size of matching = 5. Decide is maximum cardinality
|
86
|
+
matching. (How?)
|