TTK
Loading...
Searching...
No Matches
GabowTarjan.cpp
Go to the documentation of this file.
1#include <GabowTarjan.h>
2
3#include <iostream>
4#include <queue>
5#include <vector>
6
7bool ttk::GabowTarjan::DFS(int v) {
8 if(v < 0)
9 return true;
10
11 // for every adjacent vertex u of v
12 for(unsigned int i = 0; i < Connections[v].size(); ++i) {
13 const int u = Connections[v][i];
14 if(Layers[Pair[u] + 1] == Layers[v + 1] + 1) {
15 if(DFS(Pair[u])) {
16 Pair[u] = v;
17 Pair[v] = u;
18 return true;
19 }
20 }
21 }
22
23 Layers[v + 1] = -1;
24
25 return false;
26}
27
28bool ttk::GabowTarjan::BFS() {
29 std::queue<int> vertexQueue;
30
31 // For every vertex v given by PersistencePairs1
32 for(unsigned int v = 0; v < MaxSize; v++) {
33 // If its not paired to vertex in PersistencePairs2
34 if(Pair[v] < 0) {
35 // Set its layer to 0 and put it in the queue
36 Layers[v + 1] = 0;
37 vertexQueue.push(v);
38 } else {
39 // Otherwise mark it as matched (set Layer to NIL)
40 Layers[v + 1] = -1;
41 }
42 }
43
44 // Set layer for NIL
45 Layers[0] = -1;
46
47 // Search the vertices in the queue
48 while(!vertexQueue.empty()) {
49 const int v = vertexQueue.front();
50 vertexQueue.pop();
51 if(Layers[v + 1] > Layers[0]) {
52 for(unsigned int i = 0; i < Connections[v].size(); ++i) {
53 const int u = Connections[v][i];
54 // Check if the vertex has an edge to the match vertex
55 if(Layers[Pair[u] + 1] < 0) {
56 // Set the layer of the vertex (it can be NIL) which is matched to the
57 // matched vertex u
58 Layers[Pair[u] + 1] = Layers[v + 1] + 1;
59 // If the pairing vertex is not NIL add it into the queue
60 if(Pair[u] != -1)
61 vertexQueue.push(Pair[u]);
62 }
63 }
64 }
65 }
66
67 return Layers[0] != -1;
68}
69
70void ttk::GabowTarjan::HopcroftKarp(unsigned int &matching) {
71 while(BFS())
72 for(unsigned int vertex = 0; vertex < MaxSize; ++vertex) {
73 if(Pair[vertex] == -1) {
74 if(DFS(vertex))
75 ++matching;
76 }
77 }
78}
79
81 // Clear the pairing
82 Pair.clear();
83 Pair.assign(2 * MaxSize, -1);
84
85 // Clearing Layers
86 Layers.clear();
87 Layers.resize(MaxSize + 1);
88
89 // No vertices are matched
90 unsigned int matching = 0;
91 unsigned int matching0 = 0;
92
93 // Clear the connection matrix and set it to the right size
94 Connections.clear();
95 Connections.resize(MaxSize);
96
97 // The maximal weight of the edges which are used for the matching
98 double currentWeight = 0;
99
100 // First non added edge is an iterator pointing to the first edge
101 // in Edges which was added to the Connections
102 unsigned int firstNotAddedEdge = 0;
103 const unsigned int nbEdges = (unsigned int)Edges.size();
104
105 unsigned int lowerBound = 0;
106 unsigned int upperBound = nbEdges;
107 unsigned int guessEdge = (lowerBound + nbEdges) / 2;
108
109 // Repeat till all the vertices are matched
110 while(matching < MaxSize) {
111 // Save initial matching.
112 matching0 = matching;
113 const unsigned int oldGuessEdge = guessEdge;
114
115 currentWeight = Edges[guessEdge].weight;
116 while(Edges[guessEdge].weight == currentWeight && guessEdge < nbEdges)
117 ++guessEdge;
118
119 if(guessEdge >= nbEdges) {
120 this->printMsg("ran out of edges.");
121 }
122
123 // Add the edges with the current weight (distance) to the connection matrix
124 while(firstNotAddedEdge >= guessEdge) {
125 const int v1 = Edges[firstNotAddedEdge].v1;
126 const int v2 = Edges[firstNotAddedEdge].v2;
127
128 std::vector<int> vec1 = Connections[v1];
129 vec1.erase(std::remove(vec1.begin(), vec1.end(), v2), vec1.end());
130 Connections[v1] = vec1;
131
132 --firstNotAddedEdge;
133 }
134
135 // Edges[firstNotAddedEdge].weight == currentWeight && firstNotAddedEdge <
136 // nbEdges
137 while(firstNotAddedEdge < guessEdge) {
138 const int v1 = Edges[firstNotAddedEdge].v1;
139 const int v2 = Edges[firstNotAddedEdge].v2;
140
141 Connections[v1].push_back(v2);
142 ++firstNotAddedEdge;
143 }
144
145 // Clear the pairing
146 Pair.clear();
147 Pair.assign(2 * MaxSize, -1);
148 // Clearing Layers
149 Layers.clear();
150 Layers.resize(MaxSize + 1);
151
152 // Temporarily augment matching.
153 this->printMsg("Guessing for " + std::to_string(guessEdge) + "...");
154
155 matching = 0;
156 HopcroftKarp(matching);
157 // printCurrentMatching<dataType>();
158
159 if(matching >= MaxSize) {
160
161 // Reset matching.
162 matching = matching0;
163 upperBound = guessEdge;
164 guessEdge = (lowerBound + guessEdge) / 2;
165
166 // Ended binary search.
167 if(oldGuessEdge == guessEdge) {
168 this->printMsg("Binary search success.");
169 return Edges[(guessEdge > 0 ? guessEdge - 1 : guessEdge)].weight;
170 }
171
172 } else {
173
174 // Check if we did not run out of edges. This should never happen.
175 if(firstNotAddedEdge == nbEdges) {
176 this->printMsg("Not enough edges to find the matching!");
177 // return -1;
178 return currentWeight;
179 }
180
181 lowerBound = guessEdge;
182 guessEdge = (guessEdge + upperBound) / 2;
183 // Increase the value of the current weight
184 // currentWeight = Edges[firstNotAddedEdge].weight;
185
186 // Ended binary search.
187 if(oldGuessEdge == guessEdge) {
188 this->printMsg("Binary search success.");
189 return Edges[(guessEdge > 0 ? guessEdge - 1 : guessEdge)].weight;
190 }
191 }
192 }
193
194 return -1;
195}
196
198 const int size = 2 * MaxSize;
199 std::vector<int> missedPlaces;
200
201 {
202 std::stringstream msg;
203 msg << "Assignment matrix: " << std::endl;
204 for(int i = 0; i < size; ++i) {
205 const int k = Pair[i];
206 if(k < 0 || k > size)
207 missedPlaces.push_back(i);
208 for(int j = 0; j < size; ++j) {
209 msg << (j == k ? "1 " : "0 ");
210 }
211 msg << std::endl;
212 }
213 msg << "/Assignment matrix." << std::endl << std::endl;
214 this->printMsg(msg.str(), debug::Priority::VERBOSE);
215 }
216
217 {
218 std::stringstream msg;
219 msg << "Missed:" << std::endl;
220 for(unsigned int i = 0; i < missedPlaces.size(); ++i) {
221 msg << missedPlaces.at(i) << " ";
222 }
223 msg << std::endl << std::endl;
224 this->printMsg(msg.str());
225 }
226}
227
228int ttk::GabowTarjan::run(std::vector<MatchingType> &matchings) {
229 // Compute distance.
230 const double dist = this->Distance();
231 this->printMsg("Computed distance " + std::to_string(dist));
232
233 // Fill matchings.
234 matchings.clear();
235
236 for(unsigned int i = 0; i < Size1; ++i) {
237 if(Pair[i] == -1)
238 continue;
239
240 const int j = Pair[i] - MaxSize;
241 if(j <= -1 || (j < (int)Size2 && Pair[j + MaxSize] != (int)i)) {
242 this->printErr("Hopcroft-Karp built an invalid matching.");
243 // return -1;
244 }
245
246 if(j >= (int)Size2) {
247 matchings.emplace_back(i, j, (*Cptr)[i][Size2]);
248 } else {
249 matchings.emplace_back(i, j, (*Cptr)[i][j]);
250 }
251 }
252
253 for(unsigned int j = Size1; j < MaxSize; ++j) {
254 if(Pair[j] == -1)
255 continue;
256
257 const int i = Pair[j] - MaxSize - Size2;
258 if(i > -1 && (i >= (int)Size1 || Pair[i + MaxSize + Size2] != (int)j)) {
259 this->printErr("Hopcroft-Karp built an invalid matching.");
260 // return -1;
261 }
262
263 if(i <= -1) {
264 matchings.emplace_back(i, j - Size1, (*Cptr)[Size1][j - Size1]);
265 } else {
266 // Already added by symmetry.
267 matchings.emplace_back(i, j - Size1, (*Cptr)[i][j - Size1]);
268 }
269 }
270
271 return 0;
272}
int run(std::vector< MatchingType > &matchings)
void printCurrentMatching()
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)