1 package bipartitegraph
2
3 import (
4 . "github.com/onsi/gomega/matchers/support/goraph/edge"
5 . "github.com/onsi/gomega/matchers/support/goraph/node"
6 "github.com/onsi/gomega/matchers/support/goraph/util"
7 )
8
9
10
11
12 func (bg *BipartiteGraph) LargestMatching() (matching EdgeSet) {
13 paths := bg.maximalDisjointSLAPCollection(matching)
14
15 for len(paths) > 0 {
16 for _, path := range paths {
17 matching = matching.SymmetricDifference(path)
18 }
19 paths = bg.maximalDisjointSLAPCollection(matching)
20 }
21
22 return
23 }
24
25 func (bg *BipartiteGraph) maximalDisjointSLAPCollection(matching EdgeSet) (result []EdgeSet) {
26 guideLayers := bg.createSLAPGuideLayers(matching)
27 if len(guideLayers) == 0 {
28 return
29 }
30
31 used := make(map[int]bool)
32
33 for _, u := range guideLayers[len(guideLayers)-1] {
34 slap, found := bg.findDisjointSLAP(u, matching, guideLayers, used)
35 if found {
36 for _, edge := range slap {
37 used[edge.Node1] = true
38 used[edge.Node2] = true
39 }
40 result = append(result, slap)
41 }
42 }
43
44 return
45 }
46
47 func (bg *BipartiteGraph) findDisjointSLAP(
48 start Node,
49 matching EdgeSet,
50 guideLayers []NodeOrderedSet,
51 used map[int]bool,
52 ) ([]Edge, bool) {
53 return bg.findDisjointSLAPHelper(start, EdgeSet{}, len(guideLayers)-1, matching, guideLayers, used)
54 }
55
56 func (bg *BipartiteGraph) findDisjointSLAPHelper(
57 currentNode Node,
58 currentSLAP EdgeSet,
59 currentLevel int,
60 matching EdgeSet,
61 guideLayers []NodeOrderedSet,
62 used map[int]bool,
63 ) (EdgeSet, bool) {
64 used[currentNode.ID] = true
65
66 if currentLevel == 0 {
67 return currentSLAP, true
68 }
69
70 for _, nextNode := range guideLayers[currentLevel-1] {
71 if used[nextNode.ID] {
72 continue
73 }
74
75 edge, found := bg.Edges.FindByNodes(currentNode, nextNode)
76 if !found {
77 continue
78 }
79
80 if matching.Contains(edge) == util.Odd(currentLevel) {
81 continue
82 }
83
84 currentSLAP = append(currentSLAP, edge)
85 slap, found := bg.findDisjointSLAPHelper(nextNode, currentSLAP, currentLevel-1, matching, guideLayers, used)
86 if found {
87 return slap, true
88 }
89 currentSLAP = currentSLAP[:len(currentSLAP)-1]
90 }
91
92 used[currentNode.ID] = false
93 return nil, false
94 }
95
96 func (bg *BipartiteGraph) createSLAPGuideLayers(matching EdgeSet) (guideLayers []NodeOrderedSet) {
97 used := make(map[int]bool)
98 currentLayer := NodeOrderedSet{}
99
100 for _, node := range bg.Left {
101 if matching.Free(node) {
102 used[node.ID] = true
103 currentLayer = append(currentLayer, node)
104 }
105 }
106
107 if len(currentLayer) == 0 {
108 return []NodeOrderedSet{}
109 }
110 guideLayers = append(guideLayers, currentLayer)
111
112 done := false
113
114 for !done {
115 lastLayer := currentLayer
116 currentLayer = NodeOrderedSet{}
117
118 if util.Odd(len(guideLayers)) {
119 for _, leftNode := range lastLayer {
120 for _, rightNode := range bg.Right {
121 if used[rightNode.ID] {
122 continue
123 }
124
125 edge, found := bg.Edges.FindByNodes(leftNode, rightNode)
126 if !found || matching.Contains(edge) {
127 continue
128 }
129
130 currentLayer = append(currentLayer, rightNode)
131 used[rightNode.ID] = true
132
133 if matching.Free(rightNode) {
134 done = true
135 }
136 }
137 }
138 } else {
139 for _, rightNode := range lastLayer {
140 for _, leftNode := range bg.Left {
141 if used[leftNode.ID] {
142 continue
143 }
144
145 edge, found := bg.Edges.FindByNodes(leftNode, rightNode)
146 if !found || !matching.Contains(edge) {
147 continue
148 }
149
150 currentLayer = append(currentLayer, leftNode)
151 used[leftNode.ID] = true
152 }
153 }
154
155 }
156
157 if len(currentLayer) == 0 {
158 return []NodeOrderedSet{}
159 }
160 guideLayers = append(guideLayers, currentLayer)
161 }
162
163 return
164 }
165
View as plain text