TTK
Loading...
Searching...
No Matches
MergeTreePrincipalGeodesics.h
Go to the documentation of this file.
1
23
24#pragma once
25
26// ttk common includes
27#include <Debug.h>
29
30namespace ttk {
31
38 class MergeTreePrincipalGeodesics : virtual public Debug,
40
41 protected:
43 // TODO keepState works only when enabled before first computation
44 bool keepState_ = false;
45 unsigned int noProjectionStep_ = 2;
46
47 // Advanced parameters
49
50 // Old/Testing
52
53 // Filled by the algorithm
54 std::vector<double> inputToBaryDistances_;
55 std::vector<std::vector<double>> inputToGeodesicsDistances_;
59
61 double cumulVariance_ = 0.0, cumulTVariance_ = 0.0;
62
63 public:
65 // inherited from Debug: prefix will be printed at the beginning of every
66 // msg
67 this->setDebugMsgPrefix("MergeTreePrincipalGeodesics");
68#ifdef TTK_ENABLE_OPENMP
69 omp_set_nested(1);
70#endif
71 }
72
73 unsigned int getGeodesicNumber() {
74 return vS_.size();
75 }
76
77 //----------------------------------------------------------------------------
78 // OpenMP Reduction
79 //----------------------------------------------------------------------------
80 struct Compare {
81 double bestDistance = std::numeric_limits<double>::max();
82 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> bestMatching,
84 int bestIndex = 0;
85 };
86
87 //----------------------------------------------------------------------------
88 // Init
89 //----------------------------------------------------------------------------
90 template <class dataType>
91 void initVectors(int geodesicNumber,
92 ftm::MergeTree<dataType> &barycenter,
93 std::vector<ftm::MergeTree<dataType>> &trees,
94 ftm::MergeTree<dataType> &barycenter2,
95 std::vector<ftm::MergeTree<dataType>> &trees2,
96 std::vector<std::vector<double>> &v1,
97 std::vector<std::vector<double>> &v2,
98 std::vector<std::vector<double>> &trees2V1,
99 std::vector<std::vector<double>> &trees2V2) {
100 auto initializedVectorsProjection
101 = [=](int _geodesicNumber, ftm::MergeTree<dataType> &_barycenter,
102 std::vector<std::vector<double>> &_v,
103 std::vector<std::vector<double>> &_v2,
104 std::vector<std::vector<std::vector<double>>> &_vS,
105 std::vector<std::vector<std::vector<double>>> &_v2s,
106 ftm::MergeTree<dataType> &_barycenter2,
107 std::vector<std::vector<double>> &_trees2V,
108 std::vector<std::vector<double>> &_trees2V2,
109 std::vector<std::vector<std::vector<double>>> &_trees2Vs,
110 std::vector<std::vector<std::vector<double>>> &_trees2V2s,
111 bool _useSecondInput, unsigned int _noProjectionStep) {
112 return this->projectionStep(_geodesicNumber, _barycenter, _v, _v2,
113 _vS, _v2s, _barycenter2, _trees2V,
114 _trees2V2, _trees2Vs, _trees2V2s,
115 _useSecondInput, _noProjectionStep);
116 };
117
118 MergeTreeAxesAlgorithmBase::initVectors<dataType>(
119 geodesicNumber, barycenter, trees, barycenter2, trees2, v1, v2,
120 trees2V1, trees2V2, newVectorOffset_, inputToBaryDistances_,
123 initializedVectorsProjection);
124 }
125
126 //----------------------------------------------------------------------------
127 // Costs
128 //----------------------------------------------------------------------------
129 double orthogonalCost(std::vector<std::vector<std::vector<double>>> &vS,
130 std::vector<std::vector<std::vector<double>>> &v2s,
131 std::vector<std::vector<double>> &v,
132 std::vector<std::vector<double>> &v2) {
133 return verifyOrthogonality(vS, v2s, v, v2, false);
134 }
135
136 double regularizerCost(std::vector<std::vector<double>> &v,
137 std::vector<std::vector<double>> &v2) {
138 auto cost = ttk::Geometry::dotProductFlatten(v, v2)
141 return cost * cost;
142 }
143
144 double projectionCost(std::vector<std::vector<double>> &v,
145 std::vector<std::vector<double>> &v2,
146 std::vector<std::vector<std::vector<double>>> &vS,
147 std::vector<std::vector<std::vector<double>>> &v2s,
148 double optMapCost) {
149 return regularizerCost(v, v2) + orthogonalCost(vS, v2s, v, v2)
150 + optMapCost;
151 }
152
153 //----------------------------------------------------------------------------
154 // Projection
155 //----------------------------------------------------------------------------
156 template <class dataType>
158 ftm::MergeTree<dataType> &extremity,
159 std::vector<std::vector<double>> &v,
160 bool isV1,
161 bool useDoubleInput = false,
162 bool isFirstInput = true) {
163 ftm::FTMTree_MT *barycenterTree = &(barycenter.tree);
164 ftm::FTMTree_MT *extremityTree = &(extremity.tree);
165 double const t = (isV1 ? -1.0 : 1.0);
166
167 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> matching;
168 dataType distance;
169 std::vector<ftm::idNode> matchingVector;
170
171 if(extremityTree->getRealNumberOfNodes() != 0) {
172 computeOneDistance(barycenter, extremity, matching, distance, true,
173 useDoubleInput, isFirstInput);
174 getMatchingVector(barycenter, extremity, matching, matchingVector);
175 } else
176 matchingVector.resize(barycenterTree->getNumberOfNodes(),
177 std::numeric_limits<ftm::idNode>::max());
178
179 std::vector<std::vector<double>> const oriV = v;
180 for(unsigned int i = 0; i < barycenter.tree.getNumberOfNodes(); ++i) {
181 if(barycenter.tree.isNodeAlone(i))
182 continue;
183 auto matched = matchingVector[i];
184 auto birthDeathBary
185 = getParametrizedBirthDeath<dataType>(barycenterTree, i);
186 dataType birthBary = std::get<0>(birthDeathBary);
187 dataType deathBary = std::get<1>(birthDeathBary);
188 std::vector<double> newV{0.0, 0.0};
189 if(matched != std::numeric_limits<ftm::idNode>::max()) {
190 auto birthDeathMatched
191 = getParametrizedBirthDeath<dataType>(extremityTree, matched);
192 newV[0] = std::get<0>(birthDeathMatched);
193 newV[1] = std::get<1>(birthDeathMatched);
194 } else {
195 dataType projec = (birthBary + deathBary) / 2.0;
196 newV[0] = projec;
197 newV[1] = projec;
198 }
199 newV[0] = (newV[0] - birthBary) * t;
200 newV[1] = (newV[1] - deathBary) * t;
201 v[i] = newV;
202 }
203
204 // Compute distance between old and new extremity
205 double const cost = ttk::Geometry::distanceFlatten(v, oriV);
206 return cost;
207 }
208
209 template <class dataType>
210 double
212 std::vector<std::vector<double>> &v,
213 std::vector<std::vector<double>> &v2,
214 ftm::MergeTree<dataType> &barycenter2,
215 std::vector<std::vector<double>> &trees2V,
216 std::vector<std::vector<double>> &trees2V2,
217 bool useSecondInput = false) {
218 std::vector<ftm::MergeTree<dataType>> extremities(
219 (useSecondInput ? 4 : 2));
220 getInterpolation<dataType>(barycenter, v, v2, 0.0, extremities[0]);
221 getInterpolation<dataType>(barycenter, v, v2, 1.0, extremities[1]);
222 if(useSecondInput) {
223 getInterpolation<dataType>(
224 barycenter2, trees2V, trees2V2, 0.0, extremities[2]);
225 getInterpolation<dataType>(
226 barycenter2, trees2V, trees2V2, 1.0, extremities[3]);
227 }
228 double cost = 0.0;
229#ifdef TTK_ENABLE_OPENMP
230#pragma omp parallel for schedule(dynamic) \
231 num_threads(this->threadNumber_) if(parallelize_)
232#endif
233 for(unsigned int i = 0; i < extremities.size(); ++i) {
234 bool isFirstInput = (i < 2);
235 ftm::MergeTree<dataType> &baryToUse
236 = (i < 2 ? barycenter : barycenter2);
237 std::vector<std::vector<double>> &vToUse
238 = (i == 0 ? v : (i == 1 ? v2 : (i == 2 ? trees2V : trees2V2)));
239 cost
240 += barycentricProjection(baryToUse, extremities[i], vToUse,
241 (i % 2 == 0), useSecondInput, isFirstInput);
242 }
243 return cost;
244 }
245
246 // Collinearity constraint
247 void
248 trueGeneralizedGeodesicProjection(std::vector<std::vector<double>> &v1,
249 std::vector<std::vector<double>> &v2) {
250 std::vector<double> v1_flatten, v2_flatten;
253 double const v1_norm = ttk::Geometry::magnitude(v1_flatten);
254 double const v2_norm = ttk::Geometry::magnitude(v2_flatten);
255 double const beta = v2_norm / (v1_norm + v2_norm);
256 std::vector<double> v;
257 ttk::Geometry::addVectors(v1_flatten, v2_flatten, v);
258 ttk::Geometry::scaleVector(v, (1 - beta), v1_flatten);
259 ttk::Geometry::scaleVector(v, beta, v2_flatten);
262 }
263
264 void
265 orthogonalProjection(std::vector<std::vector<double>> &v1,
266 std::vector<std::vector<double>> &v2,
267 std::vector<std::vector<std::vector<double>>> &vS,
268 std::vector<std::vector<std::vector<double>>> &v2s) {
269 // Multi flatten and sum vS and v2s
270 std::vector<std::vector<double>> sumVs;
272
273 // Flatten v1 and v2
274 std::vector<double> v1_flatten, v2_flatten, v1_proj, v2_proj;
277
278 // Call Gram Schmidt
279 callGramSchmidt(sumVs, v1_flatten, v1_proj);
280 callGramSchmidt(sumVs, v2_flatten, v2_proj);
281
282 // Unflatten the resulting vectors
285 }
286
287 // TODO avoid copying vectors
288 template <class dataType>
289 double
290 projectionStep(int geodesicNumber,
291 ftm::MergeTree<dataType> &barycenter,
292 std::vector<std::vector<double>> &v,
293 std::vector<std::vector<double>> &v2,
294 std::vector<std::vector<std::vector<double>>> &vS,
295 std::vector<std::vector<std::vector<double>>> &v2s,
296 ftm::MergeTree<dataType> &barycenter2,
297 std::vector<std::vector<double>> &trees2V,
298 std::vector<std::vector<double>> &trees2V2,
299 std::vector<std::vector<std::vector<double>>> &trees2Vs,
300 std::vector<std::vector<std::vector<double>>> &trees2V2s,
301 bool useSecondInput,
302 unsigned int noProjectionStep) {
303 std::vector<std::vector<std::vector<double>>> vSConcat, v2sConcat;
304 if(useSecondInput) {
305 Timer t_vectorCopy;
306 vSConcat = vS;
307 v2sConcat = v2s;
308 for(unsigned int j = 0; j < vS.size(); ++j) {
309 vSConcat[j].insert(
310 vSConcat[j].end(), trees2Vs[j].begin(), trees2Vs[j].end());
311 v2sConcat[j].insert(
312 v2sConcat[j].end(), trees2V2s[j].begin(), trees2V2s[j].end());
313 }
314 t_vectorCopy_time_ += t_vectorCopy.getElapsedTime();
315 }
316
317 double optMapCost = 0.0;
318 for(unsigned i = 0; i < noProjectionStep; ++i) {
319 std::vector<std::vector<double>> vOld = v, v2Old = v2;
320
321 // --- Optimal mapping set projecton
324 Timer t_optMap;
325 optMapCost = optimalMappingSetProjection(
326 barycenter, v, v2, barycenter2, trees2V, trees2V2, useSecondInput);
327 printMsg("OMS Proj.", 1, t_optMap.getElapsedTime(), threadNumber_,
329
330 // ---
331 std::vector<std::vector<double>> vConcat, v2Concat;
332 if(useSecondInput) {
333 Timer t_vectorCopy;
334 vConcat = v;
335 vConcat.insert(vConcat.end(), trees2V.begin(), trees2V.end());
336 v2Concat = v2;
337 v2Concat.insert(v2Concat.end(), trees2V2.begin(), trees2V2.end());
338 t_vectorCopy_time_ += t_vectorCopy.getElapsedTime();
339 }
340
341 // --- True generalized geodesic projection
344 Timer t_trueGeod;
345 if(useSecondInput)
346 trueGeneralizedGeodesicProjection(vConcat, v2Concat);
347 else
349 printMsg("TGG Proj.", 1, t_trueGeod.getElapsedTime(), threadNumber_,
351
352 // --- Orthogonal projection
353 if(geodesicNumber != 0) {
354 printMsg("Orth. Proj.", 0, 0, threadNumber_, debug::LineMode::REPLACE,
356 Timer t_ortho;
357 if(useSecondInput) {
358 orthogonalProjection(vConcat, v2Concat, vSConcat, v2sConcat);
359 } else
360 orthogonalProjection(v, v2, vS, v2s);
361 printMsg("Orth. Proj.", 1, t_ortho.getElapsedTime(), threadNumber_,
363 }
364
365 // ---
366 if(useSecondInput) {
367 Timer t_vectorCopy;
368 for(unsigned int j = 0; j < v.size(); ++j) {
369 v[j] = vConcat[j];
370 v2[j] = v2Concat[j];
371 }
372 for(unsigned int j = 0; j < trees2V.size(); ++j) {
373 trees2V[j] = vConcat[v.size() + j];
374 trees2V2[j] = v2Concat[v.size() + j];
375 }
376 t_vectorCopy_time_ += t_vectorCopy.getElapsedTime();
377 }
378 }
379 return optMapCost;
380 }
381
382 //----------------------------------------------------------------------------
383 // Assignment
384 //----------------------------------------------------------------------------
385 template <class dataType>
387 ftm::MergeTree<dataType> &barycenter,
388 std::vector<ftm::MergeTree<dataType>> &trees,
389 std::vector<std::vector<double>> &v,
390 std::vector<std::vector<double>> &v2,
391 ftm::MergeTree<dataType> &barycenter2,
392 std::vector<ftm::MergeTree<dataType>> &trees2,
393 std::vector<std::vector<double>> &trees2V,
394 std::vector<std::vector<double>> &trees2V2,
395 std::vector<std::vector<double>> &allTreesTs,
396 std::vector<std::vector<std::vector<double>>> &vS,
397 std::vector<std::vector<std::vector<double>>> &v2s,
398 std::vector<std::vector<std::vector<double>>> &trees2Vs,
399 std::vector<std::vector<std::vector<double>>> &trees2V2s,
400 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
401 &matchings,
402 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
403 &matchings2,
404 std::vector<double> &ts,
405 std::vector<double> &distances) {
406 std::vector<std::vector<Compare>> best(
407 trees.size(), std::vector<Compare>(k_));
408
409#ifdef TTK_ENABLE_OPENMP
410#pragma omp parallel num_threads(this->threadNumber_) if(parallelize_) \
411 shared(best)
412 {
413#pragma omp single nowait
414 {
415#endif
416 for(unsigned int k = 0; k < k_; ++k) {
417 for(unsigned int i = 0; i < trees.size(); ++i) {
418#ifdef TTK_ENABLE_OPENMP
419#pragma omp task shared(best) firstprivate(i, k)
420 {
421#endif
422 double const kT = (k % 2 == 0 ? k / 2 : k_ - 1 - (int)(k / 2));
423 double t = 1.0 / (k_ - 1) * kT;
424
425 dataType distance, distance2;
426 ftm::MergeTree<dataType> interpolated;
427 auto tsToUse = (allTreesTs.size() == 0 ? std::vector<double>()
428 : allTreesTs[i]);
430 barycenter, vS, v2s, v, v2, tsToUse, t, interpolated);
431 if(interpolated.tree.getRealNumberOfNodes() != 0) {
432 computeOneDistance<dataType>(interpolated, trees[i],
433 best[i][kT].bestMatching,
434 distance, true, useDoubleInput_);
435 if(trees2.size() != 0) {
436 ftm::MergeTree<dataType> interpolated2;
437 getMultiInterpolation(barycenter2, trees2Vs, trees2V2s,
438 trees2V, trees2V2, tsToUse, t,
439 interpolated2);
440 computeOneDistance<dataType>(
441 interpolated2, trees2[i], best[i][kT].bestMatching2,
442 distance2, true, useDoubleInput_, false);
443 distance = mixDistances(distance, distance2);
444 }
445 best[i][kT].bestDistance = distance;
446 best[i][kT].bestIndex = kT;
447 }
448#ifdef TTK_ENABLE_OPENMP
449 } // pragma omp task
450#endif
451 }
452 }
453#ifdef TTK_ENABLE_OPENMP
454#pragma omp taskwait
455#endif
456
457 // Reduction
458 for(unsigned int i = 0; i < trees.size(); ++i) {
459#ifdef TTK_ENABLE_OPENMP
460#pragma omp task firstprivate(i)
461 {
462#endif
463 double bestDistance = std::numeric_limits<double>::max();
464 int bestIndex = 0;
465 for(unsigned int k = 0; k < k_; ++k) {
466 if(best[i][k].bestDistance < bestDistance) {
467 bestIndex = k;
468 bestDistance = best[i][k].bestDistance;
469 }
470 }
471 matchings[i] = best[i][bestIndex].bestMatching;
472 if(trees2.size() != 0)
473 matchings2[i] = best[i][bestIndex].bestMatching2;
474 ts[i] = best[i][bestIndex].bestIndex * 1.0 / (k_ - 1);
475 distances[i] = best[i][bestIndex].bestDistance;
476#ifdef TTK_ENABLE_OPENMP
477 } // pragma omp task
478#endif
479 }
480#ifdef TTK_ENABLE_OPENMP
481 } // pragma omp single nowait
482 } // pragma omp parallel
483#endif
484 }
485
486 template <class dataType>
488 ftm::MergeTree<dataType> &barycenter,
489 std::vector<ftm::MergeTree<dataType>> &trees,
490 std::vector<std::vector<double>> &v,
491 std::vector<std::vector<double>> &v2,
492 ftm::MergeTree<dataType> &barycenter2,
493 std::vector<ftm::MergeTree<dataType>> &trees2,
494 std::vector<std::vector<double>> &trees2V,
495 std::vector<std::vector<double>> &trees2V2,
496 std::vector<std::vector<double>> &allTreesTs,
497 std::vector<std::vector<std::vector<double>>> &vS,
498 std::vector<std::vector<std::vector<double>>> &v2s,
499 std::vector<std::vector<std::vector<double>>> &trees2Vs,
500 std::vector<std::vector<std::vector<double>>> &trees2V2s,
501 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
502 &matchings,
503 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
504 &matchings2,
505 std::vector<double> &ts,
506 std::vector<double> &distances) {
507
508 matchings.resize(trees.size());
509 matchings2.resize(trees2.size());
510 ts.resize(trees.size());
511 distances.resize(trees.size());
512
513 // Assignment
514 assignmentImpl<dataType>(barycenter, trees, v, v2, barycenter2, trees2,
515 trees2V, trees2V2, allTreesTs, vS, v2s, trees2Vs,
516 trees2V2s, matchings, matchings2, ts, distances);
517 }
518
519 //----------------------------------------------------------------------------
520 // Update
521 //----------------------------------------------------------------------------
522 template <class dataType>
524 int geodesicNumber,
525 ftm::MergeTree<dataType> &barycenter,
526 std::vector<ftm::MergeTree<dataType>> &trees,
527 std::vector<ftm::MergeTree<dataType>> &allInterpolated,
528 std::vector<std::vector<double>> &v,
529 std::vector<std::vector<double>> &v2,
530 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
531 &matchings,
532 std::vector<std::vector<double>> &tss,
533 std::vector<std::vector<double>> &vR,
534 std::vector<std::vector<double>> &vR2,
535 std::vector<bool> &isUniform) {
536
537 // Init
538 ftm::FTMTree_MT *barycenterTree = &(barycenter.tree);
539 std::vector<ftm::FTMTree_MT *> ftmTrees, allInterpolatedTrees;
540 ttk::ftm::mergeTreeToFTMTree<dataType>(trees, ftmTrees);
541 if(geodesicNumber != 0) {
542 ttk::ftm::mergeTreeToFTMTree<dataType>(
543 allInterpolated, allInterpolatedTrees);
544 }
545
546 // Get matching matrix
547 std::vector<std::vector<ftm::idNode>> matchingMatrix;
548 getMatchingMatrix(barycenter, trees, matchings, matchingMatrix);
549
550 // Update
551 for(unsigned int i = 0; i < barycenter.tree.getNumberOfNodes(); ++i) {
552 if(barycenter.tree.isNodeAlone(i))
553 continue;
554
555 // Verify that ts is not uniform
556 if(isUniform[i]) {
557 v[i] = vR[i];
558 v2[i] = vR2[i];
559 continue;
560 }
561
562 // Compute projection
563 auto birthDeathBary
564 = getParametrizedBirthDeath<dataType>(barycenterTree, i);
565 dataType birthBary = std::get<0>(birthDeathBary);
566 dataType deathBary = std::get<1>(birthDeathBary);
567 dataType projec = (birthBary + deathBary) / 2.0;
568 std::vector<dataType> allBirthBary(trees.size(), birthBary);
569 std::vector<dataType> allDeathBary(trees.size(), deathBary);
570 std::vector<dataType> allProjec(trees.size(), projec);
571
572 if(geodesicNumber != 0)
573 for(unsigned int j = 0; j < trees.size(); ++j) {
574 auto birthDeathInterpol
575 = getParametrizedBirthDeath<dataType>(allInterpolatedTrees[j], i);
576 allBirthBary[j] = std::get<0>(birthDeathInterpol);
577 allDeathBary[j] = std::get<1>(birthDeathInterpol);
578 allProjec[j] = (allBirthBary[j] + allDeathBary[j]) / 2.0;
579 }
580
581 // Compute all matched values
582 std::vector<std::vector<dataType>> allMatched(trees.size());
583 for(unsigned int j = 0; j < trees.size(); ++j) {
584 dataType birth = allProjec[j];
585 dataType death = allProjec[j];
586 if(matchingMatrix[i][j] != std::numeric_limits<ftm::idNode>::max()) {
587 auto birthDeath = getParametrizedBirthDeath<dataType>(
588 ftmTrees[j], matchingMatrix[i][j]);
589 birth = std::get<0>(birthDeath);
590 death = std::get<1>(birthDeath);
591 }
592 allMatched[j].resize(2);
593 allMatched[j][0] = birth;
594 allMatched[j][1] = death;
595 }
596
597 // Compute general terms
598 double ti_squared = 0.0, one_min_ti_squared = 0.0, ti_one_min_ti = 0.0;
599 for(auto t : tss[i]) {
600 ti_squared += t * t;
601 one_min_ti_squared += (1 - t) * (1 - t);
602 ti_one_min_ti += t * (1 - t);
603 }
604
605 // Compute multiplier
606 double multBirthV1 = 0.0, multDeathV1 = 0.0, multBirthV2 = 0.0,
607 multDeathV2 = 0.0;
608 for(unsigned int j = 0; j < trees.size(); ++j) {
609 multBirthV1
610 += tss[i][j] * (allMatched[j][0] - allBirthBary[j]) / ti_squared;
611 multDeathV1
612 += tss[i][j] * (allMatched[j][1] - allDeathBary[j]) / ti_squared;
613 multBirthV2 += (1 - tss[i][j]) * (-allMatched[j][0] + allBirthBary[j])
614 / one_min_ti_squared;
615 multDeathV2 += (1 - tss[i][j]) * (-allMatched[j][1] + allDeathBary[j])
616 / one_min_ti_squared;
617 }
618
619 // Compute new birth death
620 double newBirthV1 = 0.0, newDeathV1 = 0.0, newBirthV2 = 0.0,
621 newDeathV2 = 0.0;
622 for(unsigned int j = 0; j < trees.size(); ++j) {
623 newBirthV1 += (1 - tss[i][j])
624 * (-allMatched[j][0] + allBirthBary[j]
625 + tss[i][j] * multBirthV1);
626 newDeathV1 += (1 - tss[i][j])
627 * (-allMatched[j][1] + allDeathBary[j]
628 + tss[i][j] * multDeathV1);
629 newBirthV2 += tss[i][j]
630 * (allMatched[j][0] - allBirthBary[j]
631 + (1 - tss[i][j]) * multBirthV2);
632 newDeathV2 += tss[i][j]
633 * (allMatched[j][1] - allDeathBary[j]
634 + (1 - tss[i][j]) * multDeathV2);
635 }
636 double const divisorV1
637 = one_min_ti_squared - ti_one_min_ti * ti_one_min_ti / ti_squared;
638 double const divisorV2
639 = ti_squared - ti_one_min_ti * ti_one_min_ti / one_min_ti_squared;
640 newBirthV1 /= divisorV1;
641 newDeathV1 /= divisorV1;
642 newBirthV2 /= divisorV2;
643 newDeathV2 /= divisorV2;
644
645 // Update vectors
646 v[i][0] = newBirthV1;
647 v[i][1] = newDeathV1;
648 v2[i][0] = newBirthV2;
649 v2[i][1] = newDeathV2;
650 }
651 }
652
653 template <class dataType>
654 void
655 manageIndividualTs(int geodesicNumber,
656 ftm::MergeTree<dataType> &barycenter,
657 std::vector<ftm::MergeTree<dataType>> &trees,
658 std::vector<std::vector<double>> &v,
659 std::vector<std::vector<double>> &v2,
660 std::vector<std::vector<std::vector<double>>> &vS,
661 std::vector<std::vector<std::vector<double>>> &v2s,
662 std::vector<double> &ts,
663 std::vector<std::vector<double>> &allTreesTs,
664 std::vector<ftm::MergeTree<dataType>> &allInterpolated,
665 std::vector<bool> &isUniform,
666 std::vector<std::vector<double>> &tss,
667 unsigned int &noUniform,
668 bool &foundAllUniform) {
669 // Get multi interpolation
670 allInterpolated.resize(trees.size());
671 if(geodesicNumber != 0) {
672 for(unsigned int i = 0; i < trees.size(); ++i)
674 barycenter, vS, v2s, allTreesTs[i], allInterpolated[i]);
675 }
676
677 // Manage individuals t
678 noUniform = 0;
679 foundAllUniform = true;
680 isUniform.resize(barycenter.tree.getNumberOfNodes(), false);
681 tss.resize(barycenter.tree.getNumberOfNodes());
682 for(unsigned int i = 0; i < barycenter.tree.getNumberOfNodes(); ++i) {
683 if(barycenter.tree.isNodeAlone(i))
684 continue;
685 tss[i] = ts;
686 for(unsigned int j = 0; j < tss[i].size(); ++j) {
687 auto &treeToUse
688 = (geodesicNumber != 0 ? allInterpolated[j] : barycenter);
689 tss[i][j] = getTNew<dataType>(treeToUse, v, v2, i, ts[j]);
690 }
691 isUniform[i] = ttk::Geometry::isVectorUniform(tss[i]);
692 noUniform += isUniform[i];
693 foundAllUniform &= isUniform[i];
694 }
695 }
696
697 template <class dataType>
699 int geodesicNumber,
700 ftm::MergeTree<dataType> &barycenter,
701 std::vector<ftm::MergeTree<dataType>> &trees,
702 std::vector<std::vector<double>> &v,
703 std::vector<std::vector<double>> &v2,
704 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
705 &matchings,
706 std::vector<std::vector<std::vector<double>>> &vS,
707 std::vector<std::vector<std::vector<double>>> &v2s,
708 ftm::MergeTree<dataType> &barycenter2,
709 std::vector<ftm::MergeTree<dataType>> &trees2,
710 std::vector<std::vector<double>> &trees2V,
711 std::vector<std::vector<double>> &trees2V2,
712 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
713 &matchings2,
714 std::vector<std::vector<std::vector<double>>> &trees2Vs,
715 std::vector<std::vector<std::vector<double>>> &trees2V2s,
716 std::vector<double> &ts,
717 std::vector<std::vector<double>> &allTreesTs) {
718
719 std::vector<ftm::MergeTree<dataType>> allInterpolated, allInterpolated2;
720 std::vector<bool> isUniform, isUniform2;
721 std::vector<std::vector<double>> tss, tss2;
722 unsigned int noUniform;
723 bool foundAllUniform;
724 manageIndividualTs(geodesicNumber, barycenter, trees, v, v2, vS, v2s, ts,
725 allTreesTs, allInterpolated, isUniform, tss, noUniform,
726 foundAllUniform);
727 if(trees2.size() != 0) {
728 unsigned int noUniform2;
729 bool foundAllUniform2;
730 manageIndividualTs(geodesicNumber, barycenter2, trees2, trees2V,
731 trees2V2, trees2Vs, trees2V2s, ts, allTreesTs,
732 allInterpolated2, isUniform2, tss2, noUniform2,
733 foundAllUniform2);
734 noUniform += noUniform2;
735 foundAllUniform &= foundAllUniform2;
736 }
737
738 if(foundAllUniform) {
739 printMsg("All projection coefficients are the same.");
740 printMsg("New vectors will be initialized.");
741 newVectorOffset_ += 1;
742 initVectors(geodesicNumber, barycenter, trees, barycenter2, trees2, v,
743 v2, trees2V, trees2V2);
744 return true;
745 }
746 std::vector<std::vector<double>> vR, vR2, trees2VR, trees2VR2;
747 if(noUniform != 0) {
748 printMsg("Found " + std::to_string(noUniform)
749 + " uniform coefficients.");
750 initVectors(geodesicNumber, barycenter, trees, barycenter2, trees2, vR,
751 vR2, trees2VR, trees2VR2);
752 }
753
754 updateClosedForm(geodesicNumber, barycenter, trees, allInterpolated, v,
755 v2, matchings, tss, vR, vR2, isUniform);
756 if(trees2.size() != 0) {
757 updateClosedForm(geodesicNumber, barycenter2, trees2, allInterpolated2,
758 trees2V, trees2V2, matchings2, tss2, trees2VR,
759 trees2VR2, isUniform2);
760 copyMinMaxPairVector(v, v2, trees2V, trees2V2);
761 }
762 return false;
763 }
764
765 template <class dataType>
767 int geodesicNumber,
768 ftm::MergeTree<dataType> &barycenter,
769 std::vector<ftm::MergeTree<dataType>> &trees,
770 std::vector<std::vector<double>> &v,
771 std::vector<std::vector<double>> &v2,
772 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
773 &matchings,
774 std::vector<std::vector<std::vector<double>>> &vS,
775 std::vector<std::vector<std::vector<double>>> &v2s,
776 ftm::MergeTree<dataType> &barycenter2,
777 std::vector<ftm::MergeTree<dataType>> &trees2,
778 std::vector<std::vector<double>> &trees2V,
779 std::vector<std::vector<double>> &trees2V2,
780 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
781 &matchings2,
782 std::vector<std::vector<std::vector<double>>> &trees2Vs,
783 std::vector<std::vector<std::vector<double>>> &trees2V2s,
784 std::vector<double> &ts,
785 std::vector<std::vector<double>> &allTreesTs) {
786 return updateClosedFormStep<dataType>(
787 geodesicNumber, barycenter, trees, v, v2, matchings, vS, v2s,
788 barycenter2, trees2, trees2V, trees2V2, matchings2, trees2Vs, trees2V2s,
789 ts, allTreesTs);
790 }
791
792 //----------------------------------------------------------------------------
793 // Main functions
794 //----------------------------------------------------------------------------
795 template <class dataType>
796 bool convergenceStep(std::vector<double> &distances,
797 std::vector<std::vector<double>> &v,
798 std::vector<std::vector<double>> &v2,
799 dataType &oldFrechetEnergy,
800 dataType &minFrechetEnergy,
801 int &cptBlocked,
802 bool &converged,
803 double optMapCost) {
804 bool isBestEnergy = false;
805
806 // Reconstruction cost (main energy)
807 double frechetEnergy = 0;
808 for(unsigned int i = 0; i < distances.size(); ++i)
809 frechetEnergy += distances[i] * distances[i] / distances.size();
810 std::stringstream ssEnergy;
811 ssEnergy << "Energy = " << frechetEnergy;
812 printMsg(ssEnergy.str());
813
814 // Prop. cost
815 std::stringstream ssReg;
816 auto reg = regularizerCost(v, v2);
817 ssReg << "Prop. cost = " << reg;
818 printMsg(ssReg.str());
819
820 // Ortho. cost
821 std::stringstream ssOrthoCost;
822 auto orthoCost = orthogonalCost(vS_, v2s_, v, v2);
823 ssOrthoCost << "Ortho. cost = " << orthoCost;
824 printMsg(ssOrthoCost.str());
825
826 // Map. cost
827 std::stringstream ssOptMapCost;
828 ssOptMapCost << "Map. cost = " << optMapCost;
829 printMsg(ssOptMapCost.str());
830
831 // Detect convergence
832 double tol = 0.01;
833 tol = oldFrechetEnergy / 125.0;
834 converged = std::abs(frechetEnergy - oldFrechetEnergy) < tol;
835 oldFrechetEnergy = frechetEnergy;
836
837 if(frechetEnergy + ENERGY_COMPARISON_TOLERANCE < minFrechetEnergy) {
838 minFrechetEnergy = frechetEnergy;
839 cptBlocked = 0;
840 isBestEnergy = true;
841 }
842 if(not converged) {
843 cptBlocked += (minFrechetEnergy < frechetEnergy) ? 1 : 0;
844 converged = (cptBlocked >= 10);
845 }
846
847 return isBestEnergy;
848 }
849
850 template <class dataType>
851 void
852 computePrincipalGeodesic(unsigned int geodesicNumber,
853 ftm::MergeTree<dataType> &barycenter,
854 std::vector<ftm::MergeTree<dataType>> &trees,
855 ftm::MergeTree<dataType> &barycenter2,
856 std::vector<ftm::MergeTree<dataType>> &trees2) {
857 // ----- Init Parameters
859 Timer t_init;
860 std::vector<std::vector<double>> v, v2, trees2V, trees2V2;
861 initVectors<dataType>(geodesicNumber, barycenter, trees, barycenter2,
862 trees2, v, v2, trees2V, trees2V2);
864 printMsg("Init", 1, t_init.getElapsedTime(), threadNumber_);
865
866 std::vector<std::vector<double>> bestV, bestV2, bestTrees2V, bestTrees2V2;
867 std::vector<double> bestTs, bestDistances;
868 int bestIteration = 0;
869
870 // ----- Init Loop
871 dataType oldFrechetEnergy, minFrechetEnergy;
872 int cptBlocked, iteration = 0;
873 auto initLoop = [&]() {
874 oldFrechetEnergy = -1;
875 minFrechetEnergy = std::numeric_limits<dataType>::max();
876 cptBlocked = 0;
877 iteration = 0;
878 };
879 initLoop();
880
881 // ----- Algorithm
882 double optMapCost = 0.0;
883 bool converged = false;
884 while(not converged) {
885 std::stringstream ss;
886 ss << "Iteration " << iteration;
888 printMsg(ss.str());
889
890 // --- Assignment
891 printMsg("Assignment", 0, 0, threadNumber_, debug::LineMode::REPLACE);
892 Timer t_assignment;
893 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
894 matchings, matchings2;
895 std::vector<double> ts, distances;
896 assignmentStep(barycenter, trees, v, v2, barycenter2, trees2, trees2V,
898 matchings, matchings2, ts, distances);
899 inputToGeodesicsDistances_[geodesicNumber] = distances;
900 allTs_[geodesicNumber] = ts;
901 printMsg("Assignment", 1, t_assignment.getElapsedTime(), threadNumber_);
902
903 // --- Convergence
904 bool isBest = convergenceStep(distances, v, v2, oldFrechetEnergy,
905 minFrechetEnergy, cptBlocked, converged,
906 optMapCost);
907 if(isBest) {
908 Timer t_copy;
909 bestV = v;
910 bestV2 = v2;
911 bestTrees2V = trees2V;
912 bestTrees2V2 = trees2V2;
913 bestTs = ts;
914 bestDistances = distances;
915 bestIteration = iteration;
917 }
918 if(converged)
919 break;
920
921 // --- Update
923 Timer t_update;
924 bool reset
925 = updateStep(geodesicNumber, barycenter, trees, v, v2, matchings, vS_,
926 v2s_, barycenter2, trees2, trees2V, trees2V2, matchings2,
928 printMsg("Update", 1, t_update.getElapsedTime(), threadNumber_);
929 if(reset) {
930 initLoop();
931 continue;
932 }
933
934 // --- Projection
935 printMsg("Projection", 0, 0, threadNumber_, debug::LineMode::REPLACE);
936 Timer t_projection;
937 optMapCost
938 = projectionStep(geodesicNumber, barycenter, v, v2, vS_, v2s_,
939 barycenter2, trees2V, trees2V2, trees2Vs_,
940 trees2V2s_, (trees2.size() != 0), noProjectionStep_);
941 auto projectionTime
942 = t_projection.getElapsedTime() - t_vectorCopy_time_;
944 t_vectorCopy_time_ = 0.0;
945 printMsg("Projection", 1, projectionTime, threadNumber_);
946
947 ++iteration;
948 }
950 printMsg("Best energy is " + std::to_string(minFrechetEnergy)
951 + " (iteration " + std::to_string(bestIteration) + " / "
952 + std::to_string(iteration) + ")");
954
955 Timer t_copy;
956 v = bestV;
957 v2 = bestV2;
958 trees2V = bestTrees2V;
959 trees2V2 = bestTrees2V2;
960 inputToGeodesicsDistances_[geodesicNumber] = bestDistances;
961 allTs_[geodesicNumber] = bestTs;
962
963 vS_.push_back(v);
964 v2s_.push_back(v2);
965 trees2Vs_.push_back(trees2V);
966 trees2V2s_.push_back(trees2V2);
969 }
970
971 template <class dataType>
972 void
974 std::vector<ftm::MergeTree<dataType>> &trees2) {
975 // --- Compute barycenter
976 ftm::MergeTree<dataType> barycenter, barycenter2;
977 if(not keepState_ or not barycenterWasComputed_) {
978 Timer t_barycenter;
979 printMsg("Barycenter", 0, t_barycenter.getElapsedTime(), threadNumber_,
981 computeOneBarycenter<dataType>(trees, barycenter, baryMatchings_,
983 mergeTreeTemplateToDouble(barycenter, barycenterBDT_);
984 if(trees2.size() != 0) {
985 std::vector<double> baryDistances2;
986 computeOneBarycenter<dataType>(trees2, barycenter2, baryMatchings2_,
987 baryDistances2, useDoubleInput_,
988 false);
989 mergeTreeTemplateToDouble(barycenter2, barycenterInput2BDT_);
990 for(unsigned int i = 0; i < inputToBaryDistances_.size(); ++i)
992 = mixDistances(inputToBaryDistances_[i], baryDistances2[i]);
993
994 verifyMinMaxPair(barycenter, barycenter2);
995 }
996 printMsg("Barycenter", 1, t_barycenter.getElapsedTime(), threadNumber_);
998 } else {
999 printMsg("KeepState is enabled and barycenter was already computed");
1000 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
1001 barycenterBDT_, barycenter);
1002 if(trees2.size() != 0) {
1003 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
1004 barycenterInput2BDT_, barycenter2);
1005 }
1006 }
1007 printMsg(barycenter.tree.printTreeStats().str());
1008 mergeTreeTemplateToDouble(barycenter, barycenter_);
1009 if(trees2.size() != 0) {
1010 printMsg(barycenter2.tree.printTreeStats().str());
1011 mergeTreeTemplateToDouble(barycenter2, barycenterInput2_);
1012 }
1013
1014 // --- Compute global variance
1015 double const globalVariance
1017
1018 // --- Manage maximum number of geodesics
1019 unsigned int maxNoGeodesics = barycenter.tree.getRealNumberOfNodes() * 2;
1020 if(trees2.size() != 0)
1021 maxNoGeodesics += barycenter2.tree.getRealNumberOfNodes() * 2;
1022 if(maxNoGeodesics < numberOfAxes_) {
1023 std::stringstream ss;
1024 ss << numberOfAxes_ << " principal geodesics are asked but only "
1025 << maxNoGeodesics << " can be computed.";
1026 printMsg(ss.str());
1027 printMsg("(the maximum is twice the number of persistence pairs in the "
1028 "barycenter)");
1029 numberOfAxes_ = maxNoGeodesics;
1030 }
1031
1032 // --- Init
1033 unsigned int const oldNoGeod = allTs_.size();
1034 if(not keepState_) {
1035 allTs_.resize(numberOfAxes_, std::vector<double>(trees.size()));
1037 numberOfAxes_, std::vector<double>(trees.size()));
1038 vS_.clear();
1039 v2s_.clear();
1040 trees2Vs_.clear();
1041 trees2V2s_.clear();
1042 allTreesTs_.clear();
1043 srand(deterministic_ ? 7 : time(nullptr));
1044 t_vectorCopy_time_ = 0.0;
1046 cumulVariance_ = 0.0;
1047 cumulTVariance_ = 0.0;
1048 } else {
1049 allTs_.resize(numberOfAxes_, std::vector<double>(trees.size()));
1052 numberOfAxes_, std::vector<double>(trees.size()));
1053 if(oldNoGeod != 0)
1054 printMsg(
1055 "KeepState is enabled, restart the computation at geodesic number "
1056 + std::to_string(oldNoGeod));
1057 }
1058
1059 // --- Compute each geodesic
1060 for(unsigned int geodNum = oldNoGeod; geodNum < numberOfAxes_;
1061 ++geodNum) {
1063 std::stringstream ss;
1064 ss << "Compute geodesic " << geodNum;
1065 printMsg(ss.str());
1066
1067 // - Compute geodesic
1068 computePrincipalGeodesic<dataType>(
1069 geodNum, barycenter, trees, barycenter2, trees2);
1070
1071 // - Compute explained variance
1073 barycenter, trees, barycenter2, trees2, geodNum, globalVariance);
1074 }
1075 }
1076
1077 template <class dataType>
1078 void execute(std::vector<ftm::MergeTree<dataType>> &trees,
1079 std::vector<ftm::MergeTree<dataType>> &trees2) {
1080 // --- Preprocessing
1081 Timer t_preprocess;
1082 preprocessingTrees<dataType>(trees, treesNodeCorr_);
1083 if(trees2.size() != 0)
1084 preprocessingTrees<dataType>(trees2, trees2NodeCorr_);
1085 printMsg(
1086 "Preprocessing", 1, t_preprocess.getElapsedTime(), threadNumber_);
1087 useDoubleInput_ = (trees2.size() != 0);
1088
1089 // --- Compute principal geodesics
1090 Timer t_total;
1091 computePrincipalGeodesics<dataType>(trees, trees2);
1092 auto totalTime = t_total.getElapsedTime() - t_allVectorCopy_time_;
1094 printMsg("Total time", 1, totalTime, threadNumber_);
1095 ftm::MergeTree<dataType> barycenter;
1096 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(barycenter_, barycenter);
1097
1098 // - Compute merge tree geodesic extremities
1099 computeGeodesicExtremities<dataType>();
1100
1101 // - Compute branches correlation matrix
1102 computeBranchesCorrelationMatrix<dataType>(barycenter, trees);
1103
1104 // --- Reconstruction
1106 auto reconstructionError = computeReconstructionError(
1107 barycenter, trees, vS_, v2s_, allTreesTs_);
1108 std::stringstream ss;
1109 ss << "Reconstruction Error = " << reconstructionError;
1110 printMsg(ss.str());
1111 }
1112
1113 // --- Postprocessing
1114 if(normalizedWasserstein_) { // keep BDT if input is a PD
1115 postprocessingPipeline<double>(&(barycenter_.tree));
1116 if(trees2.size() != 0)
1117 postprocessingPipeline<double>(&(barycenterInput2_.tree));
1118 }
1119
1120 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(barycenter_, barycenter);
1121 for(unsigned int i = 0; i < trees.size(); ++i) {
1122 postprocessingPipeline<dataType>(&(trees[i].tree));
1123 convertBranchDecompositionMatching<dataType>(
1124 &(barycenter.tree), &(trees[i].tree), baryMatchings_[i]);
1125 }
1126 for(unsigned int i = 0; i < trees2.size(); ++i)
1127 postprocessingPipeline<dataType>(&(trees2[i].tree));
1128 }
1129
1130 // ----------------------------------------
1131 // End functions
1132 // ----------------------------------------
1133 void copyMinMaxPairVector(std::vector<std::vector<double>> &v,
1134 std::vector<std::vector<double>> &v2,
1135 std::vector<std::vector<double>> &trees2V,
1136 std::vector<std::vector<double>> &trees2V2) {
1137 auto root = barycenter_.tree.getRoot();
1138 auto root2 = barycenterInput2_.tree.getRoot();
1139 trees2V[root2] = v[root];
1140 trees2V2[root2] = v2[root];
1141 }
1142
1143 template <class dataType>
1145 allScaledTs_.resize(allTs_.size(), std::vector<double>(allTs_[0].size()));
1146 ftm::MergeTree<dataType> barycenter, barycenter2;
1147 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(barycenter_, barycenter);
1148 if(trees2NodeCorr_.size() != 0)
1149 ttk::ftm::mergeTreeDoubleToTemplate<dataType>(
1150 barycenterInput2_, barycenter2);
1151#ifdef TTK_ENABLE_OPENMP
1152#pragma omp parallel for schedule(dynamic) \
1153 num_threads(this->threadNumber_) if(parallelize_)
1154#endif
1155 for(unsigned int i = 0; i < numberOfAxes_; ++i) {
1156 ftm::MergeTree<dataType> extremityV1, extremityV2;
1157 getInterpolation<dataType>(
1158 barycenter, vS_[i], v2s_[i], 0.0, extremityV1);
1159 getInterpolation<dataType>(
1160 barycenter, vS_[i], v2s_[i], 1.0, extremityV2);
1161 // Get distance
1162 dataType distance;
1164 extremityV1, extremityV2, distance, true, useDoubleInput_);
1165 if(trees2NodeCorr_.size() != 0) {
1166 ftm::MergeTree<dataType> extremity2V1, extremity2V2;
1167 getInterpolation<dataType>(
1168 barycenter2, trees2Vs_[i], trees2V2s_[i], 0.0, extremity2V1);
1169 getInterpolation<dataType>(
1170 barycenter2, trees2Vs_[i], trees2V2s_[i], 1.0, extremity2V2);
1171 // Get distance
1172 dataType distance2;
1173 computeOneDistance(extremity2V1, extremity2V2, distance2, true,
1174 useDoubleInput_, false);
1175 distance = mixDistances(distance, distance2);
1176 }
1177 for(unsigned int j = 0; j < allTs_[i].size(); ++j)
1178 allScaledTs_[i][j] = allTs_[i][j] * distance;
1179 }
1180 }
1181
1182 template <class dataType>
1190
1191 // ----------------------------------------
1192 // Message
1193 // ----------------------------------------
1194 template <class dataType>
1196 std::vector<ftm::MergeTree<dataType>> &trees,
1197 ftm::MergeTree<dataType> &barycenter2,
1198 std::vector<ftm::MergeTree<dataType>> &trees2,
1199 int geodesicNumber,
1200 double globalVariance) {
1201 bool const printOriginalVariances = false;
1202 bool const printSurfaceVariance = false;
1203 bool const printTVariances = true;
1204
1205 if(printOriginalVariances) {
1206 // Variance
1207 double variance = computeExplainedVariance<dataType>(
1208 barycenter, trees, vS_[geodesicNumber], v2s_[geodesicNumber],
1209 allTs_[geodesicNumber]);
1210 double const variancePercent = variance / globalVariance * 100.0;
1211 std::stringstream ssVariance, ssCumul;
1212 ssVariance << "Variance explained : "
1213 << round(variancePercent * 100.0) / 100.0 << " %";
1214 printMsg(ssVariance.str());
1215
1216 // Cumul Variance
1217 cumulVariance_ += variance;
1218 double const cumulVariancePercent
1219 = cumulVariance_ / globalVariance * 100.0;
1220 ssCumul << "Cumulative explained variance : "
1221 << round(cumulVariancePercent * 100.0) / 100.0 << " %";
1222 printMsg(ssCumul.str());
1223 }
1224
1225 if(printSurfaceVariance) {
1226 // Surface Variance
1227 double surfaceVariance = computeSurfaceExplainedVariance<dataType>(
1228 barycenter, trees, vS_, v2s_, allTs_);
1229 double const surfaceVariancePercent
1230 = surfaceVariance / globalVariance * 100.0;
1231 std::stringstream ssSurface;
1232 ssSurface << "Surface Variance explained : "
1233 << round(surfaceVariancePercent * 100.0) / 100.0 << " %";
1234 printMsg(ssSurface.str());
1235 }
1236
1237 if(printTVariances) {
1238 // T-Variance
1239 double tVariance;
1240 if(trees2.size() != 0) {
1241 tVariance = computeExplainedVarianceT(
1242 barycenter, vS_[geodesicNumber], v2s_[geodesicNumber], barycenter2,
1243 trees2Vs_[geodesicNumber], trees2V2s_[geodesicNumber],
1244 allTs_[geodesicNumber]);
1245 } else
1246 tVariance = computeExplainedVarianceT(barycenter, vS_[geodesicNumber],
1247 v2s_[geodesicNumber],
1248 allTs_[geodesicNumber]);
1249 double const tVariancePercent = tVariance / globalVariance * 100.0;
1250 std::stringstream ssTVariance, ssCumulT;
1251 ssTVariance << "Explained T-Variance : "
1252 << round(tVariancePercent * 100.0) / 100.0 << " %";
1253 printMsg(ssTVariance.str());
1254
1255 // Cumul T-Variance
1256 cumulTVariance_ += tVariance;
1257 double const cumulTVariancePercent
1258 = cumulTVariance_ / globalVariance * 100.0;
1259 ssCumulT << "Cumulative explained T-Variance : "
1260 << round(cumulTVariancePercent * 100.0) / 100.0 << " %";
1261 printMsg(ssCumulT.str());
1262 }
1263 }
1264
1265 //----------------------------------------------------------------------------
1266 // Utils
1267 //----------------------------------------------------------------------------
1268 double
1269 verifyOrthogonality(std::vector<std::vector<std::vector<double>>> &vS,
1270 std::vector<std::vector<std::vector<double>>> &v2s,
1271 bool doPrint = true);
1272 double
1273 verifyOrthogonality(std::vector<std::vector<std::vector<double>>> &vS,
1274 std::vector<std::vector<std::vector<double>>> &v2s,
1275 std::vector<std::vector<double>> &v,
1276 std::vector<std::vector<double>> &v2,
1277 bool doPrint = true);
1278
1279 template <class dataType>
1280 dataType computeVarianceFromDistances(std::vector<dataType> &distances);
1281
1282 template <class dataType>
1283 double
1285 std::vector<ftm::MergeTree<dataType>> &trees,
1286 std::vector<std::vector<double>> &v,
1287 std::vector<std::vector<double>> &v2,
1288 std::vector<double> &ts,
1289 bool computeGlobalVariance = false);
1290
1291 template <class dataType>
1293 std::vector<ftm::MergeTree<dataType>> &trees);
1294
1295 template <class dataType>
1297 ftm::MergeTree<dataType> &barycenter,
1298 std::vector<ftm::MergeTree<dataType>> &trees,
1299 std::vector<std::vector<std::vector<double>>> &vS,
1300 std::vector<std::vector<std::vector<double>>> &v2s,
1301 std::vector<std::vector<double>> &ts);
1302
1303 template <class dataType>
1305 std::vector<std::vector<double>> &v,
1306 std::vector<std::vector<double>> &v2,
1307 std::vector<double> &ts,
1308 std::vector<double> &distances,
1309 bool useDoubleInput = false,
1310 bool isFirstInput = true);
1311
1312 template <class dataType>
1314 std::vector<std::vector<double>> &v,
1315 std::vector<std::vector<double>> &v2,
1316 std::vector<double> &ts);
1317
1318 template <class dataType>
1320 std::vector<std::vector<double>> &v,
1321 std::vector<std::vector<double>> &v2,
1322 ftm::MergeTree<dataType> &barycenter2,
1323 std::vector<std::vector<double>> &trees2V,
1324 std::vector<std::vector<double>> &trees2V2,
1325 std::vector<double> &ts);
1326
1327 // ----------------------------------------
1328 // Testing
1329 // ----------------------------------------
1330 template <class dataType>
1332 ftm::MergeTree<dataType> &mTree) {
1333 if(not normalizedWasserstein_) // isPersistenceDiagram
1334 return;
1335 ftm::FTMTree_MT *tree = &(mTree.tree);
1336 std::stringstream ss;
1337 auto birthDeathRoot = tree->getMergedRootBirthDeath<dataType>();
1338 auto birthRoot = std::get<0>(birthDeathRoot);
1339 auto deathRoot = std::get<1>(birthDeathRoot);
1340 bool found = false;
1341 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) {
1342 if(tree->isNodeAlone(i))
1343 continue;
1344 auto birthDeath = tree->getBirthDeath<dataType>(i);
1345 auto birth = std::get<0>(birthDeath);
1346 auto death = std::get<1>(birthDeath);
1347 if(birth < birthRoot or birth > deathRoot or death < birthRoot
1348 or death > deathRoot) {
1349 ss << tree->printNode2<dataType>(i).str() << std::endl;
1350 found = true;
1351 }
1352 }
1353 if(found) {
1354 ftm::FTMTree_MT *tree1 = &(mTree1.tree);
1355 printMsg("Tree1 root:");
1356 printMsg(tree1->printNode2<dataType>(tree1->getRoot()).str());
1357 printMsg("Tree root:");
1358 printMsg(tree->printNode2<dataType>(tree->getRoot()).str());
1359 printMsg("Tree merged root:");
1360 printMsg(tree->printMergedRoot<dataType>().str());
1361 printMsg("Bad pairs:");
1362 printMsg(ss.str());
1363 printErr("[computePrincipalGeodesics] tree root is not min max.");
1364 }
1365 }
1366 }; // MergeTreePrincipalGeodesics class
1367} // namespace ttk
1368
#define ENERGY_COMPARISON_TOLERANCE
Minimalist debugging class.
Definition Debug.h:88
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
std::vector< std::vector< int > > trees2NodeCorr_
void computeOneDistance(ftm::MergeTree< dataType > &tree1, ftm::MergeTree< dataType > &tree2, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, dataType &distance, bool isCalled=false, bool useDoubleInput=false, bool isFirstInput=true)
void getMatchingMatrix(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< ftm::idNode > > &matchingMatrix)
void computeBranchesCorrelationMatrix(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &baryMatchings, std::vector< std::vector< double > > &allTs, std::vector< std::vector< double > > &branchesCorrelationMatrix, std::vector< std::vector< double > > &persCorrelationMatrix)
void getMatchingVector(ftm::MergeTree< dataType > &barycenter, ftm::MergeTree< dataType > &tree, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matchings, std::vector< ftm::idNode > &matchingVector)
double mixDistances(dataType distance1, dataType distance2)
std::vector< std::vector< int > > treesNodeCorr_
std::vector< std::vector< double > > allTreesTs_
std::vector< std::vector< std::vector< double > > > v2s_
std::vector< std::vector< std::vector< double > > > trees2V2s_
void getMultiInterpolation(ftm::MergeTree< dataType > &barycenter, std::vector< std::vector< double * > > &vS, std::vector< std::vector< double * > > &v2s, size_t vSize, std::vector< double > &ts, ftm::MergeTree< dataType > &interpolated, bool transposeVector=true)
std::vector< std::vector< std::vector< double > > > vS_
std::vector< std::vector< double > > allTs_
std::vector< std::vector< double > > branchesCorrelationMatrix_
std::vector< std::vector< double > > persCorrelationMatrix_
std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > baryMatchings_
std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > baryMatchings2_
std::vector< std::vector< std::vector< double > > > trees2Vs_
std::vector< std::vector< double > > allScaledTs_
dataType computeReconstructionError(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &inputTrees, std::vector< std::vector< double * > > &vS, std::vector< std::vector< double * > > &v2s, size_t vSize, std::vector< std::vector< double > > &allTreesTs, std::vector< double > &reconstructionErrors, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, bool transposeVector=true)
void callGramSchmidt(std::vector< std::vector< double > > &vS, std::vector< double > &v, std::vector< double > &newV)
double verifyOrthogonality(std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, bool doPrint=true)
void computeProjectionDistances(ftm::MergeTree< dataType > &barycenter, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< double > &ts, std::vector< double > &distances, bool useDoubleInput=false, bool isFirstInput=true)
void orthogonalProjection(std::vector< std::vector< double > > &v1, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s)
void copyMinMaxPairVector(std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2)
void trueGeneralizedGeodesicProjection(std::vector< std::vector< double > > &v1, std::vector< std::vector< double > > &v2)
double computeExplainedVariance(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< double > &ts, bool computeGlobalVariance=false)
double projectionStep(int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, ftm::MergeTree< dataType > &barycenter2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2, std::vector< std::vector< std::vector< double > > > &trees2Vs, std::vector< std::vector< std::vector< double > > > &trees2V2s, bool useSecondInput, unsigned int noProjectionStep)
void computeBranchesCorrelationMatrix(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees)
void computePrincipalGeodesics(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< ftm::MergeTree< dataType > > &trees2)
bool updateStep(int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings2, std::vector< std::vector< std::vector< double > > > &trees2Vs, std::vector< std::vector< std::vector< double > > > &trees2V2s, std::vector< double > &ts, std::vector< std::vector< double > > &allTreesTs)
void assignmentStep(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2, std::vector< std::vector< double > > &allTreesTs, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, std::vector< std::vector< std::vector< double > > > &trees2Vs, std::vector< std::vector< std::vector< double > > > &trees2V2s, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings2, std::vector< double > &ts, std::vector< double > &distances)
void execute(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< ftm::MergeTree< dataType > > &trees2)
dataType computeVarianceFromDistances(std::vector< dataType > &distances)
bool updateClosedFormStep(int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings2, std::vector< std::vector< std::vector< double > > > &trees2Vs, std::vector< std::vector< std::vector< double > > > &trees2V2s, std::vector< double > &ts, std::vector< std::vector< double > > &allTreesTs)
double regularizerCost(std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2)
double computeSurfaceExplainedVariance(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, std::vector< std::vector< double > > &ts)
void assignmentImpl(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2, std::vector< std::vector< double > > &allTreesTs, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, std::vector< std::vector< std::vector< double > > > &trees2Vs, std::vector< std::vector< std::vector< double > > > &trees2V2s, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings2, std::vector< double > &ts, std::vector< double > &distances)
void printIterationVariances(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2, int geodesicNumber, double globalVariance)
double orthogonalCost(std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2)
std::vector< std::vector< double > > inputToGeodesicsDistances_
void verifyMinMaxPair(ftm::MergeTree< dataType > &mTree1, ftm::MergeTree< dataType > &mTree)
void initVectors(int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2, std::vector< std::vector< double > > &v1, std::vector< std::vector< double > > &v2, std::vector< std::vector< double > > &trees2V1, std::vector< std::vector< double > > &trees2V2)
void manageIndividualTs(int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, std::vector< double > &ts, std::vector< std::vector< double > > &allTreesTs, std::vector< ftm::MergeTree< dataType > > &allInterpolated, std::vector< bool > &isUniform, std::vector< std::vector< double > > &tss, unsigned int &noUniform, bool &foundAllUniform)
double computeExplainedVarianceT(ftm::MergeTree< dataType > &barycenter, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< double > &ts)
double barycentricProjection(ftm::MergeTree< dataType > &barycenter, ftm::MergeTree< dataType > &extremity, std::vector< std::vector< double > > &v, bool isV1, bool useDoubleInput=false, bool isFirstInput=true)
double projectionCost(std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::vector< double > > > &vS, std::vector< std::vector< std::vector< double > > > &v2s, double optMapCost)
void computePrincipalGeodesic(unsigned int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, ftm::MergeTree< dataType > &barycenter2, std::vector< ftm::MergeTree< dataType > > &trees2)
double computeGlobalVariance(ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees)
double optimalMappingSetProjection(ftm::MergeTree< dataType > &barycenter, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, ftm::MergeTree< dataType > &barycenter2, std::vector< std::vector< double > > &trees2V, std::vector< std::vector< double > > &trees2V2, bool useSecondInput=false)
bool convergenceStep(std::vector< double > &distances, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, dataType &oldFrechetEnergy, dataType &minFrechetEnergy, int &cptBlocked, bool &converged, double optMapCost)
void updateClosedForm(int geodesicNumber, ftm::MergeTree< dataType > &barycenter, std::vector< ftm::MergeTree< dataType > > &trees, std::vector< ftm::MergeTree< dataType > > &allInterpolated, std::vector< std::vector< double > > &v, std::vector< std::vector< double > > &v2, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< double > > &tss, std::vector< std::vector< double > > &vR, std::vector< std::vector< double > > &vR2, std::vector< bool > &isUniform)
double getElapsedTime()
Definition Timer.h:15
idNode getNumberOfNodes() const
Definition FTMTree_MT.h:389
std::tuple< dataType, dataType > getBirthDeath(idNode nodeId)
std::stringstream printNode2(idNode nodeId, bool doPrint=true)
std::tuple< dataType, dataType > getMergedRootBirthDeath()
bool isNodeAlone(idNode nodeId)
std::stringstream printMergedRoot(bool doPrint=true)
std::stringstream printTreeStats(bool doPrint=true)
int scaleVector(const T *a, const T factor, T *out, const int &dimension=3)
Definition Geometry.cpp:647
int addVectors(const T *a, const T *b, T *out, const int &dimension=3)
Definition Geometry.cpp:610
T dotProductFlatten(const std::vector< std::vector< T > > &vA, const std::vector< std::vector< T > > &vB)
Definition Geometry.cpp:412
int flattenMultiDimensionalVector(const std::vector< std::vector< T > > &a, std::vector< T > &out)
Definition Geometry.cpp:742
bool isVectorUniform(const std::vector< T > &a)
Definition Geometry.cpp:719
T magnitudeFlatten(const std::vector< std::vector< T > > &v)
Definition Geometry.cpp:519
void transposeMatrix(const std::vector< std::vector< T > > &a, std::vector< std::vector< T > > &out)
Definition Geometry.cpp:818
int unflattenMultiDimensionalVector(const std::vector< T > &a, std::vector< std::vector< T > > &out, const int &no_columns=2)
Definition Geometry.cpp:762
T magnitude(const T *v, const int &dimension=3)
Definition Geometry.cpp:509
T distanceFlatten(const std::vector< std::vector< T > > &p0, const std::vector< std::vector< T > > &p1)
Definition Geometry.cpp:379
int multiAddVectorsFlatten(const std::vector< std::vector< std::vector< T > > > &a, const std::vector< std::vector< std::vector< T > > > &b, std::vector< std::vector< T > > &out)
Definition Geometry.cpp:635
The Topology ToolKit.
T end(std::pair< T, T > &p)
Definition ripserpy.cpp:483
T begin(std::pair< T, T > &p)
Definition ripserpy.cpp:479
std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > bestMatching2
std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > bestMatching
ftm::FTMTree_MT tree
Definition FTMTree_MT.h:903
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)