bipartite_graph 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f94717ca0e980c145bc9eff819518bfc01054c2f
4
- data.tar.gz: c88a438ba62df2581510b302298b004e69251d9b
3
+ metadata.gz: 4ea037a79cf9dbd088c8d4351057ea39f62bdfa3
4
+ data.tar.gz: ab0f8cc6fb801adf2a3460b01e45a36e7679638e
5
5
  SHA512:
6
- metadata.gz: 0f886ec5b380f849f11b2c9da2e24e052124a7e69e30794700baf3eb032c853e1d5d97bd3a943a2ce77fc2a066eede3e051e93080798f78398bb312370fd9c00
7
- data.tar.gz: e3513a47e120dfdfcbf403478d7d8815fe77c2c4d82c3cdc939b43fecda1b4d8a6b6ecf2fcaa9100665a4657c9a94ab7fb230c3ef87cf53b295d6c7c1a22df5b
6
+ metadata.gz: 0737da7745f9f99d8f2c7983d61d4b6277a840417afd5db021076733a024b811a345915fd1a6a9ac1a4ad1803a71a37bbb6b81f02f49a812e91609533977c7c6
7
+ data.tar.gz: 8a1b329e9270035a201e55cc036b29ed103e42073dcecea9c9f9d80e2e4aec7f8dbe356ca37e8389ed89f84d90e02c008f6d935cddcc3314fcb695700de978e6
@@ -1,5 +1,6 @@
1
1
  require "bipartite_graph/version"
2
2
  require "bipartite_graph/graph"
3
+ require "bipartite_graph/complete_graph"
3
4
  require "bipartite_graph/edge"
4
5
  require "bipartite_graph/edge_set"
5
6
  require "bipartite_graph/hungarian_algorithm"
@@ -0,0 +1,34 @@
1
+ require 'delegate'
2
+
3
+ module BipartiteGraph
4
+ class CompleteGraph < SimpleDelegator
5
+ class FakeNode; end
6
+
7
+ def initialize(graph)
8
+ @original_graph = graph
9
+ @complete_graph = Graph.new
10
+
11
+ sinks = graph.sinks.dup
12
+ sink_count = sinks.length
13
+ sources = graph.sources.dup
14
+ source_count = sources.length
15
+
16
+ if sink_count > source_count
17
+ (sink_count - source_count).times { sources << FakeNode.new }
18
+ elsif source_count > sink_count
19
+ (source_count - sink_count).times { sinks << FakeNode.new }
20
+ end
21
+
22
+ sources.each do |source|
23
+ sinks.each do |sink|
24
+ edge = graph.edge_between(source, sink)
25
+ weight = edge ? edge.weight : 0
26
+ @complete_graph.add_edge(source, sink, weight)
27
+ end
28
+ end
29
+
30
+ super(@complete_graph)
31
+ end
32
+
33
+ end
34
+ end
@@ -23,6 +23,9 @@ module BipartiteGraph
23
23
  def length
24
24
  to_a.length
25
25
  end
26
+ def empty?
27
+ to_a.empty?
28
+ end
26
29
 
27
30
  def from(node_or_nodes)
28
31
  from_set = Set.new(Array(node_or_nodes))
@@ -26,6 +26,10 @@ module BipartiteGraph
26
26
  @nodes[key]
27
27
  end
28
28
 
29
+ def edge_between(a, b)
30
+ # horrendously inefficient
31
+ @edges.find {|e| e.from == a && e.to == b }
32
+ end
29
33
 
30
34
  def max_weight_matching
31
35
  HungarianAlgorithm.new(self).solution
@@ -1,13 +1,32 @@
1
1
  module BipartiteGraph
2
2
  class HungarianAlgorithm
3
- attr_reader :labelling, :matching, :graph
3
+ attr_reader :labelling, :matching, :graph, :original_graph
4
4
 
5
5
  def initialize(graph)
6
- @graph = graph
7
- @labelling = Labelling.new(graph)
6
+ @original_graph = graph
7
+ @graph = BipartiteGraph::CompleteGraph.new(graph)
8
+ @labelling = Labelling.new(@graph)
8
9
  @matching = create_initial_matching
9
10
  end
10
11
 
12
+ def solution
13
+ while matching.weight != labelling.total
14
+ root = (graph.sources - matching.sources).first
15
+ add_to_matching(root)
16
+ end
17
+
18
+ restricted_matching(matching, original_graph)
19
+ end
20
+
21
+ def restricted_matching(matching, graph)
22
+ m = Matching.new(graph)
23
+
24
+ matching.edges.each do |edge|
25
+ m.add_edge(edge) if edge.weight > 0 # will exclude fake nodes as they're
26
+ # only reachable from 0 edges
27
+ end
28
+ m
29
+ end
11
30
 
12
31
  def create_initial_matching
13
32
  eq_graph = labelling.equality_graph
@@ -117,15 +136,6 @@ module BipartiteGraph
117
136
  end
118
137
  end
119
138
 
120
- def solution
121
- while matching.weight != labelling.total
122
- root = (graph.sources - matching.sources).first
123
- add_to_matching(root)
124
- end
125
-
126
- matching
127
- end
128
-
129
139
  def equality_graph
130
140
  labelling.equality_graph
131
141
  end
@@ -1,3 +1,3 @@
1
1
  module BipartiteGraph
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -25,7 +25,6 @@ describe "weighted matchings" do
25
25
  end
26
26
 
27
27
  describe "simple example 2" do
28
-
29
28
  before do
30
29
  [
31
30
  ['x1', 'y1', 3],
@@ -46,7 +45,7 @@ describe "weighted matchings" do
46
45
  matching = graph.max_weight_matching.edges.map {|e| [e.from, e.to] }
47
46
 
48
47
  expect(matching).to match_array([
49
- ['x1', 'y2'], ['x2', 'y1'], ['x3', 'y4'], ['x4', 'y3']
48
+ ['x2', 'y1'], ['x3', 'y2'], ['x4', 'y3'] # ['x1', 'y4'] with weight 0
50
49
  ])
51
50
  end
52
51
  end
@@ -68,4 +67,30 @@ describe "weighted matchings" do
68
67
  ])
69
68
  end
70
69
  end
70
+
71
+ describe "not connected-enough example" do
72
+ # the algorithm will run on some non-completely-connected graphs, but
73
+ # won't complete on all of them
74
+ # this example is constructed from simple example 2, so that the algorithm
75
+ # will fail (unless extra edges are added)
76
+ before do
77
+ [
78
+ ['x1', 'y1', 3],
79
+ ['x2', 'y1', 11],
80
+ ['x3', 'y1', 10],
81
+ ['x3', 'y3', 8],
82
+ ['x3', 'y4', 7],
83
+ ['x4', 'y3', 6],
84
+ ['x4', 'y4', 4]
85
+ ].each { |from, to, weight| graph.add_edge(from, to, weight) }
86
+ end
87
+
88
+ it "finds the solution" do
89
+ matching = graph.max_weight_matching.edges.map {|e| [e.from, e.to] }
90
+
91
+ expect(matching).to match_array([
92
+ ['x2', 'y1'], ['x3', 'y4'], ['x4', 'y3']
93
+ ])
94
+ end
95
+ end
71
96
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bipartite_graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Close
@@ -74,6 +74,7 @@ files:
74
74
  - bipartite_graph.gemspec
75
75
  - lib/bipartite_graph.rb
76
76
  - lib/bipartite_graph/alternating_tree.rb
77
+ - lib/bipartite_graph/complete_graph.rb
77
78
  - lib/bipartite_graph/edge.rb
78
79
  - lib/bipartite_graph/edge_set.rb
79
80
  - lib/bipartite_graph/graph.rb