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