TTK
Loading...
Searching...
No Matches
SeparatrixStability.cpp
Go to the documentation of this file.
1#include <AssignmentAuction.h>
3
4#include <cmath>
5
7 // inherited from Debug: prefix will be printed at the beginning of every msg
8 this->setDebugMsgPrefix("SeparatrixStability");
9}
10
11void ttk::SeparatrixStability::assignmentSolver(
12 std::vector<std::vector<double>> &costMatrix,
13 std::vector<ttk::MatchingType> &matching) {
14 if(costMatrix.size() > 0) {
16 solver.setInput(costMatrix);
17 solver.run(matching);
18 solver.clearMatrix();
19 }
20}
21
22void ttk::SeparatrixStability::buildCostMatrix(
23 const std::vector<std::array<double, 3>> &coords1,
24 const std::vector<std::array<double, 3>> &coords2,
25 const std::vector<double> &scalars1,
26 const std::vector<double> &scalars2,
27 std::vector<std::vector<double>> &costMatrix) {
28 int size_1 = coords1.size();
29 int size_2 = coords2.size();
30 if(size_1 == size_2) {
31 costMatrix.resize(size_1);
32 for(int i = 0; i < size_1; i++) {
33 costMatrix[i].resize(size_1);
34 }
35 for(int i = 0; i < size_1; i++) {
36 for(int j = 0; j < size_1; j++) {
37 costMatrix[i][j]
38 = std::sqrt(Px * std::pow(coords1[i][0] - coords2[j][0], 2)
39 + Py * std::pow(coords1[i][1] - coords2[j][1], 2)
40 + Pz * std::pow(coords1[i][2] - coords2[j][2], 2)
41 + Pf * std::pow(scalars1[i] - scalars2[j], 2));
42 }
43 }
44 } else {
45
46 costMatrix.resize(size_1 + size_2);
47 for(int i = 0; i < size_1 + size_2; i++) {
48 costMatrix[i].resize(size_1 + size_2);
49 }
50 for(int i = 0; i < size_1; i++) {
51 for(int j = 0; j < size_2; j++) {
52 costMatrix[i][j]
53 = std::sqrt(Px * std::pow(coords1[i][0] - coords2[j][0], 2)
54 + Py * std::pow(coords1[i][1] - coords2[j][1], 2)
55 + Pz * std::pow(coords1[i][2] - coords2[j][2], 2));
56 }
57 }
58 for(int i = size_1; i < size_1 + size_2; i++) {
59 for(int j = 0; j < size_2; j++) {
60 costMatrix[i][j] = epsilon;
61 }
62 }
63 for(int i = 0; i < size_1; i++) {
64 for(int j = size_2; j < size_2 + size_1; j++) {
65 costMatrix[i][j] = epsilon;
66 }
67 }
68 }
69}
70
71int ttk::SeparatrixStability::buildMatchingsWithOtherBlocks(
72 const std::vector<std::vector<std::array<double, 3>>> &coords,
73 const std::vector<std::vector<double>> &scalars,
74 const int &block_id,
75 std::vector<std::vector<MatchingType>> &matchings) {
76
77 int n_blocks = coords.size();
78
79 for(int i = 0; i < n_blocks; i++) {
80 if(i == block_id)
81 continue;
82 std::vector<std::vector<double>> costMatrix;
83 int blockIdInMatchingVector = i < block_id ? i : i - 1;
84 buildCostMatrix(
85 coords[block_id], coords[i], scalars[block_id], scalars[i], costMatrix);
86 assignmentSolver(costMatrix, matchings[blockIdInMatchingVector]);
87 }
88 return 1;
89}
90
91int ttk::SeparatrixStability::buildOccurrenceArraysFull(
92 const std::vector<GraphMatrixFull> &adjacencyMatrices,
93 const int &n_separatrices,
94 const std::vector<std::vector<std::array<double, 3>>> &coordsSource,
95 const std::vector<std::vector<std::array<double, 3>>> &coordsDestination,
96 const std::vector<std::vector<double>> &scalarsSource,
97 const std::vector<std::vector<double>> &scalarsDestination,
98 const int &block_id,
99 std::vector<int> &edgeOccurrences,
100 std::vector<bool> &isIsomorphicWith,
101 std::vector<std::vector<int>> &matchingArraySource,
102 std::vector<std::vector<int>> &matchingArrayDestination,
103 std::vector<std::vector<int>> &matchingArraySeparatrix) {
104
105 int n_blocks = adjacencyMatrices.size();
106 int n_sourceThisBlock = adjacencyMatrices[block_id].size();
107 int n_destinationThisBlock = adjacencyMatrices[block_id][0].size();
108
109 isIsomorphicWith.resize(n_blocks, true);
110 matchingArraySource.resize(n_blocks, std::vector<int>());
111 for(int k = 0; k < n_blocks; k++) {
112 matchingArraySource[k].resize(adjacencyMatrices[k].size(), -2);
113 }
114 matchingArrayDestination.resize(n_blocks, std::vector<int>());
115 for(int k = 0; k < n_blocks; k++) {
116 matchingArrayDestination[k].resize(adjacencyMatrices[k][0].size(), -2);
117 }
118
119 edgeOccurrences.resize(n_separatrices, 1);
120
121 std::vector<std::vector<MatchingType>> matchingsSource(n_blocks - 1);
122 std::vector<std::vector<MatchingType>> matchingsDestination(n_blocks - 1);
123
124 buildMatchingsWithOtherBlocks(
125 coordsSource, scalarsSource, block_id, matchingsSource);
126 buildMatchingsWithOtherBlocks(
127 coordsDestination, scalarsDestination, block_id, matchingsDestination);
128
129 for(int k = 0; k < n_blocks; k++) {
130
131 int n_source = adjacencyMatrices[k].size();
132 int n_destination = adjacencyMatrices[k][0].size();
133
134 if(k == block_id) {
135 for(int i = 0; i < n_destination; i++) {
136 matchingArrayDestination[k][i] = i;
137 }
138 for(int i = 0; i < n_source; i++) {
139 matchingArraySource[k][i] = i;
140 }
141 for(int i = 0; i < n_separatrices; i++) {
142 matchingArraySeparatrix[k][i] = i;
143 }
144 continue;
145 }
146
147 int otherBlockdIdMatchingsVector = k < block_id ? k : k - 1;
148 int matchingsSourceSize
149 = n_source == n_sourceThisBlock ? n_source : n_source + n_sourceThisBlock;
150 int matchingsDestinationSize = n_destination == n_destinationThisBlock
151 ? n_destination
152 : n_destination + n_destinationThisBlock;
153 for(int i = 0; i < matchingsSourceSize; i++) {
154 for(int j = 0; j < matchingsDestinationSize; j++) {
155 int thisBlockSourceId
156 = std::get<0>(matchingsSource[otherBlockdIdMatchingsVector][i]);
157 int thisBlockDestinationId
158 = std::get<0>(matchingsDestination[otherBlockdIdMatchingsVector][j]);
159 int otherBlockSourceId
160 = std::get<1>(matchingsSource[otherBlockdIdMatchingsVector][i]);
161 int otherBlockDestinationId
162 = std::get<1>(matchingsDestination[otherBlockdIdMatchingsVector][j]);
163 if(otherBlockDestinationId >= n_destination
164 || otherBlockSourceId >= n_source)
165 continue;
166 if(thisBlockSourceId >= n_sourceThisBlock) {
167 matchingArraySource[k][otherBlockSourceId] = -1;
168 }
169 if(thisBlockDestinationId >= n_destinationThisBlock) {
170 matchingArrayDestination[k][otherBlockDestinationId] = -1;
171 }
172 if(thisBlockDestinationId >= n_destinationThisBlock
173 || thisBlockSourceId >= n_sourceThisBlock)
174 continue;
175
176 matchingArrayDestination[k][otherBlockDestinationId]
177 = thisBlockDestinationId;
178 matchingArraySource[k][otherBlockSourceId] = thisBlockSourceId;
179 if(adjacencyMatrices[block_id][thisBlockSourceId]
180 [thisBlockDestinationId]
181 != -1
182 && adjacencyMatrices[k][otherBlockSourceId][otherBlockDestinationId]
183 != -1) {
184 int separatriceId = adjacencyMatrices[block_id][thisBlockSourceId]
185 [thisBlockDestinationId];
186 int separatriceIdInOtherBlock
187 = adjacencyMatrices[k][otherBlockSourceId][otherBlockDestinationId];
188 edgeOccurrences[separatriceId]++;
189 matchingArraySeparatrix[k][separatriceIdInOtherBlock] = separatriceId;
190 } else if((adjacencyMatrices[block_id][thisBlockSourceId]
191 [thisBlockDestinationId]
192 != -1)
193 ^ (adjacencyMatrices[k][otherBlockSourceId]
194 [otherBlockDestinationId]
195 != -1)) {
196 isIsomorphicWith[k] = false;
197 }
198 }
199 }
200 }
201 // re-index the matching id for the source point so that they are different
202 // from the destination point id
203 int offset
204 = std::max_element(
205 matchingArrayDestination.begin(), matchingArrayDestination.end(),
206 [](const std::vector<int> &a, const std::vector<int> &b) {
207 return a.size() < b.size();
208 })
209 ->size();
210 for(int i = 0; i < n_blocks; i++) {
211 int sourceSize = matchingArraySource[i].size();
212 for(int j = 0; j < sourceSize; j++) {
213 matchingArraySource[i][j] += offset;
214 }
215 }
216
217 return 1;
218}
219
220void ttk::SeparatrixStability::computeGraphMinor(
221 const GraphMatrixFull &adjacencyMatrixFull,
222 GraphMatrixMinor &adjacencyMatrix) {
223 int n_row = adjacencyMatrixFull.size();
224 int n_col = adjacencyMatrixFull[0].size();
225 adjacencyMatrix.resize(n_col);
226 for(int i = 0; i < n_col; i++) {
227 adjacencyMatrix[i].resize(n_col);
228 }
229
230 for(int i = 0; i < n_row; i++) {
231 for(int j = 0; j < n_col; j++) {
232 if(adjacencyMatrixFull[i][j] != -1) {
233 for(int k = 0; k < j; k++) {
234 if(adjacencyMatrixFull[i][k] != -1) {
235 std::pair<int, int> newEdge = std::make_pair(
236 adjacencyMatrixFull[i][j], adjacencyMatrixFull[i][k]);
237 adjacencyMatrix[k][j].push_back(newEdge);
238 }
239 }
240 }
241 }
242 }
243}
244
245int ttk::SeparatrixStability::buildOccurrenceArraysMinor(
246 const std::vector<GraphMatrixFull> &adjacencyMatricesFull,
247 const int &n_separatrices,
248 const std::vector<std::vector<std::array<double, 3>>> &coords,
249 const std::vector<std::vector<double>> &scalars,
250 const int &block_id,
251 std::vector<int> &edgeOccurrences,
252 std::vector<bool> &isIsomorphicWith,
253 std::vector<std::vector<int>> &matchingArray,
254 std::vector<std::vector<int>> &matchingArraySeparatrix) {
255
256 int n_blocks = adjacencyMatricesFull.size();
257 isIsomorphicWith.resize(n_blocks, true);
258
259 std::vector<GraphMatrixMinor> adjacencyMatricesMinor(n_blocks);
260
261 for(int i = 0; i < n_blocks; i++) {
262 computeGraphMinor(adjacencyMatricesFull[i], adjacencyMatricesMinor[i]);
263 }
264
265 int n_pointsThisBlock = adjacencyMatricesMinor[block_id].size();
266
267 matchingArray.resize(n_blocks, std::vector<int>());
268 for(int i = 0; i < n_blocks; i++) {
269 matchingArray[i].resize(adjacencyMatricesMinor[i].size(), -2);
270 }
271
272 for(int i = 0; i < n_pointsThisBlock; i++) {
273 matchingArray[block_id][i] = i;
274 }
275
276 edgeOccurrences.resize(n_separatrices);
277
278 for(int i = 0; i < n_pointsThisBlock; i++) {
279 for(int j = 0; j < n_pointsThisBlock; j++) {
280 if(!adjacencyMatricesMinor[block_id][i][j].empty()) {
281 ;
282 for(auto edge : adjacencyMatricesMinor[block_id][i][j]) {
283 edgeOccurrences[edge.first] = 1;
284 edgeOccurrences[edge.second] = 1;
285 }
286 }
287 }
288 }
289
290 int mergeSeparatrixCount{};
291 for(int i = 0; i < n_pointsThisBlock; i++) {
292 for(int j = 0; j < n_pointsThisBlock; j++) {
293 if(!adjacencyMatricesMinor[block_id][i][j].empty()) {
294 for(auto e : adjacencyMatricesMinor[block_id][i][j]) {
295 int sepId_1 = e.first;
296 int sepId_2 = e.second;
297 matchingArraySeparatrix[block_id][sepId_1] = mergeSeparatrixCount;
298 matchingArraySeparatrix[block_id][sepId_2] = mergeSeparatrixCount;
299 mergeSeparatrixCount++;
300 }
301 }
302 }
303 }
304
305 std::vector<std::vector<MatchingType>> matchings(n_blocks - 1);
306 buildMatchingsWithOtherBlocks(coords, scalars, block_id, matchings);
307
308 for(int k = 0; k < n_blocks; k++) {
309 if(k == block_id)
310 continue;
311 int n_points = adjacencyMatricesMinor[k].size();
312
313 int otherBlockdIdMatchingsVector = k < block_id ? k : k - 1;
314 int n_matchings
315 = n_points == n_pointsThisBlock ? n_points : n_points + n_pointsThisBlock;
316
317 for(int i = 0; i < n_matchings; i++) {
318 int thisBlockPointId
319 = std::get<0>(matchings[otherBlockdIdMatchingsVector][i]);
320 int otherBlockPointId
321 = std::get<1>(matchings[otherBlockdIdMatchingsVector][i]);
322 if(otherBlockPointId >= n_points)
323 continue;
324 if(thisBlockPointId >= n_pointsThisBlock) {
325 matchingArray[k][otherBlockPointId] = -1;
326 continue;
327 }
328 matchingArray[k][otherBlockPointId]
329 = matchingArray[block_id][thisBlockPointId];
330 }
331
332 for(int i = 0; i < n_matchings; i++) {
333 for(int j = i + 1; j < n_matchings; j++) {
334 int tmp2 = std::get<0>(matchings[otherBlockdIdMatchingsVector][j]);
335 int tmp1 = std::get<0>(matchings[otherBlockdIdMatchingsVector][i]);
336 int thisBlockVertex1 = std::min(tmp1, tmp2);
337 int thisBlockVertex2 = std::max(tmp1, tmp2);
338 tmp1 = std::get<1>(matchings[otherBlockdIdMatchingsVector][i]);
339 tmp2 = std::get<1>(matchings[otherBlockdIdMatchingsVector][j]);
340 int otherBlockVertex1 = std::min(tmp1, tmp2);
341 int otherBlockVertex2 = std::max(tmp1, tmp2);
342 if(thisBlockVertex1 >= n_pointsThisBlock
343 || thisBlockVertex2 >= n_pointsThisBlock
344 || otherBlockVertex1 >= n_points || otherBlockVertex2 >= n_points)
345 continue;
346 bool existsInOtherBlock
347 = !adjacencyMatricesMinor[k][otherBlockVertex1][otherBlockVertex2]
348 .empty();
349
350 if(!adjacencyMatricesMinor[block_id][thisBlockVertex1][thisBlockVertex2]
351 .empty()
352 && existsInOtherBlock > 0) {
353 for(auto edge : adjacencyMatricesMinor[block_id][thisBlockVertex1]
354 [thisBlockVertex2]) {
355 std::pair<int, int> edgeInOtherBlock
356 = adjacencyMatricesMinor[k][otherBlockVertex1][otherBlockVertex2]
357 [0];
358 edgeOccurrences[edge.first] += existsInOtherBlock;
359 edgeOccurrences[edge.second] += existsInOtherBlock;
360 matchingArraySeparatrix[k][edgeInOtherBlock.first]
361 = matchingArraySeparatrix[block_id][edge.first];
362 matchingArraySeparatrix[k][edgeInOtherBlock.second]
363 = matchingArraySeparatrix[block_id][edge.second];
364 }
365 } else if((!adjacencyMatricesMinor[block_id][thisBlockVertex1]
366 [thisBlockVertex2]
367 .empty())
368 ^ existsInOtherBlock) {
369 isIsomorphicWith[k] = false;
370 }
371 }
372 }
373 }
374 return 1;
375}
376
378 const std::vector<GraphMatrixFull> &adjacencyMatrices,
379 const std::vector<int> &separatrixCountForEachBlock,
380 const std::vector<std::vector<std::array<double, 3>>> &coordsSource,
381 const std::vector<std::vector<std::array<double, 3>>> &coordsDestination,
382 const std::vector<std::vector<double>> &scalarsSource,
383 const std::vector<std::vector<double>> &scalarsDestination,
384 const bool &mergeEdgesOnSaddles,
385 std::vector<std::vector<int>> &edgesOccurrencesForEachBlock,
386 std::vector<std::vector<bool>> &isomorphismForEachBlock,
387 std::vector<std::vector<std::vector<int>>> &matchingArrayForEachBlockSource,
388 std::vector<std::vector<std::vector<int>>>
389 &matchingArrayForEachBlockDestination,
390 std::vector<std::vector<std::vector<int>>>
391 &matchingArraySeparatrixForEachBlock) {
392
393 int n_blocks = adjacencyMatrices.size();
394 int status{};
395 for(int i = 0; i < n_blocks; i++) {
396 matchingArraySeparatrixForEachBlock[i].resize(n_blocks);
397 for(int j = 0; j < n_blocks; j++) {
398 matchingArraySeparatrixForEachBlock[i][j].resize(
399 separatrixCountForEachBlock[j], -1);
400 }
401 }
402
403#ifdef TTK_ENABLE_OPENMP
404#pragma omp parallel for num_threads(threadNumber_)
405#endif // TTK_ENABLE_OPENMP
406 for(int i = 0; i < n_blocks; i++) {
407 if(!mergeEdgesOnSaddles) {
408 status = this->buildOccurrenceArraysFull(
409 adjacencyMatrices, separatrixCountForEachBlock[i], coordsSource,
410 coordsDestination, scalarsSource, scalarsDestination, i,
411 edgesOccurrencesForEachBlock[i], isomorphismForEachBlock[i],
412 matchingArrayForEachBlockSource[i],
413 matchingArrayForEachBlockDestination[i],
414 matchingArraySeparatrixForEachBlock[i]);
415 } else {
416 status = this->buildOccurrenceArraysMinor(
417 adjacencyMatrices, separatrixCountForEachBlock[i], coordsDestination,
418 scalarsDestination, i, edgesOccurrencesForEachBlock[i],
419 isomorphismForEachBlock[i], matchingArrayForEachBlockDestination[i],
420 matchingArraySeparatrixForEachBlock[i]);
421 }
422 }
423
424 return status;
425}
int run(std::vector< MatchingType > &matchings) override
virtual int setInput(std::vector< std::vector< dataType > > &C_)
virtual void clearMatrix()
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int buildOccurrenceArrays(const std::vector< GraphMatrixFull > &adjacencyMatrices, const std::vector< int > &separatrixCountForEachBlock, const std::vector< std::vector< std::array< double, 3 > > > &coordsSource, const std::vector< std::vector< std::array< double, 3 > > > &coordsDestination, const std::vector< std::vector< double > > &scalarsSource, const std::vector< std::vector< double > > &scalarsDestination, const bool &mergeEdgesOnSaddles, std::vector< std::vector< int > > &edgesOccurrencesForEachBlock, std::vector< std::vector< bool > > &isomorphismForEachBlock, std::vector< std::vector< std::vector< int > > > &matchingArrayForEachBlockSource, std::vector< std::vector< std::vector< int > > > &matchingArrayForEachBlockDestination, std::vector< std::vector< std::vector< int > > > &matchingArraySeparatrixForEachBlock)