Loading...
Searching...
No Matches
Persistence_landscape.h
1/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2 * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3 * Author(s): Pawel Dlotko
4 *
5 * Copyright (C) 2016 Inria
6 *
7 * Modification(s):
8 * - YYYY/MM Author: Description of the modification
9 */
10
11#ifndef PERSISTENCE_LANDSCAPE_H_
12#define PERSISTENCE_LANDSCAPE_H_
13
14// gudhi include
15#include <gudhi/read_persistence_from_file.h>
16#include <gudhi/common_persistence_representations.h>
17
18// standard include
19#include <cmath>
20#include <iostream>
21#include <vector>
22#include <limits>
23#include <fstream>
24#include <sstream>
25#include <algorithm>
26#include <string>
27#include <utility>
28#include <functional>
29
30namespace Gudhi {
31namespace Persistence_representations {
32
33// pre declaration
35template <typename operation>
36Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
37 const Persistence_landscape& land2);
38
61 public:
65 Persistence_landscape() { this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals(); }
66
70 Persistence_landscape(const std::vector<std::pair<double, double> >& p,
71 size_t number_of_levels = std::numeric_limits<size_t>::max());
72
78 Persistence_landscape(const char* filename, size_t dimension = std::numeric_limits<unsigned>::max(),
79 size_t number_of_levels = std::numeric_limits<size_t>::max());
80
84 void load_landscape_from_file(const char* filename);
85
89 void print_to_file(const char* filename) const;
90
95 double compute_integral_of_landscape() const;
96
100 double compute_integral_of_a_level_of_a_landscape(size_t level) const;
101
106 double compute_integral_of_landscape(double p) const; // this function compute integral of p-th power of landscape.
107
113 double compute_value_at_a_given_point(unsigned level, double x) const;
114
120 friend std::ostream& operator<<(std::ostream& out, Persistence_landscape& land);
121
122 template <typename operation>
123 friend Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
124 const Persistence_landscape& land2);
125
130 const Persistence_landscape& land2) {
131 return operation_on_pair_of_landscapes<std::plus<double> >(land1, land2);
132 }
133
138 const Persistence_landscape& land2) {
139 return operation_on_pair_of_landscapes<std::minus<double> >(land1, land2);
140 }
141
146 return add_two_landscapes(first, second);
147 }
148
153 return subtract_two_landscapes(first, second);
154 }
155
159 friend Persistence_landscape operator*(const Persistence_landscape& first, double con) {
160 return first.multiply_lanscape_by_real_number_not_overwrite(con);
161 }
162
166 friend Persistence_landscape operator*(double con, const Persistence_landscape& first) {
167 return first.multiply_lanscape_by_real_number_not_overwrite(con);
168 }
169
174 *this = *this + rhs;
175 return *this;
176 }
177
182 *this = *this - rhs;
183 return *this;
184 }
185
191 *this = *this * x;
192 return *this;
193 }
194
199 if (x == 0) throw("In operator /=, division by 0. Program terminated.");
200 *this = *this * (1 / x);
201 return *this;
202 }
203
207 bool operator==(const Persistence_landscape& rhs) const;
208
212 bool operator!=(const Persistence_landscape& rhs) const { return !((*this) == rhs); }
213
217 double compute_maximum() const {
218 double maxValue = 0;
219 if (this->land.size()) {
220 maxValue = -std::numeric_limits<int>::max();
221 for (size_t i = 0; i != this->land[0].size(); ++i) {
222 if (this->land[0][i].second > maxValue) maxValue = this->land[0][i].second;
223 }
224 }
225 return maxValue;
226 }
227
231 double compute_minimum() const {
232 double minValue = 0;
233 if (this->land.size()) {
234 minValue = std::numeric_limits<int>::max();
235 for (size_t i = 0; i != this->land[0].size(); ++i) {
236 if (this->land[0][i].second < minValue) minValue = this->land[0][i].second;
237 }
238 }
239 return minValue;
240 }
241
245 double compute_norm_of_landscape(double i) {
247 if (i < std::numeric_limits<double>::max()) {
248 return compute_distance_of_landscapes(*this, l, i);
249 } else {
251 }
252 }
253
257 double operator()(unsigned level, double x) const { return this->compute_value_at_a_given_point(level, x); }
258
263 const Persistence_landscape& second);
264
268 friend double compute_distance_of_landscapes(const Persistence_landscape& first, const Persistence_landscape& second,
269 double p);
270
278
279 Persistence_landscape* new_abs();
280
284 size_t size() const { return this->land.size(); }
285
289 double find_max(unsigned lambda) const;
290
294 friend double compute_inner_product(const Persistence_landscape& l1, const Persistence_landscape& l2);
295
296 // Implementations of functions for various concepts.
297
306 double project_to_R(int number_of_function) const {
307 return this->compute_integral_of_a_level_of_a_landscape((size_t)number_of_function);
308 }
309
314 size_t number_of_projections_to_R() const { return this->number_of_functions_for_projections_to_reals; }
315
320 std::vector<double> vectorize(int number_of_function) const {
321 // TODO(PD) think of something smarter over here
322 std::vector<double> v;
323 if ((size_t)number_of_function > this->land.size()) {
324 return v;
325 }
326 v.reserve(this->land[number_of_function].size());
327 for (size_t i = 0; i != this->land[number_of_function].size(); ++i) {
328 v.push_back(this->land[number_of_function][i].second);
329 }
330 return v;
331 }
336 size_t number_of_vectorize_functions() const { return this->number_of_functions_for_vectorization; }
337
342 void compute_average(const std::vector<Persistence_landscape*>& to_average) {
343 bool dbg = false;
344
345 if (dbg) {
346 std::clog << "to_average.size() : " << to_average.size() << std::endl;
347 }
348
349 std::vector<Persistence_landscape*> nextLevelMerge(to_average.size());
350 for (size_t i = 0; i != to_average.size(); ++i) {
351 nextLevelMerge[i] = to_average[i];
352 }
353 bool is_this_first_level = true; // in the loop, we will create dynamically a number of intermediate complexes. We
354 // have to clean that up, but we cannot erase the initial landscapes we have
355 // to average. In this case, we simply check if the nextLevelMerge are the input landscapes or the ones created in
356 // that loop by using this extra variable.
357
358 while (nextLevelMerge.size() != 1) {
359 if (dbg) {
360 std::clog << "nextLevelMerge.size() : " << nextLevelMerge.size() << std::endl;
361 }
362 std::vector<Persistence_landscape*> nextNextLevelMerge;
363 nextNextLevelMerge.reserve(to_average.size());
364 for (size_t i = 0; i < nextLevelMerge.size(); i = i + 2) {
365 if (dbg) {
366 std::clog << "i : " << i << std::endl;
367 }
369 if (i + 1 != nextLevelMerge.size()) {
370 (*l) = (*nextLevelMerge[i]) + (*nextLevelMerge[i + 1]);
371 } else {
372 (*l) = *nextLevelMerge[i];
373 }
374 nextNextLevelMerge.push_back(l);
375 }
376 if (dbg) {
377 std::clog << "After this iteration \n";
378 getchar();
379 }
380
381 if (!is_this_first_level) {
382 // deallocate the memory if the vector nextLevelMerge do not consist of the initial landscapes
383 for (size_t i = 0; i != nextLevelMerge.size(); ++i) {
384 delete nextLevelMerge[i];
385 }
386 }
387 is_this_first_level = false;
388 nextLevelMerge.swap(nextNextLevelMerge);
389 }
390 (*this) = (*nextLevelMerge[0]);
391 if (!is_this_first_level) delete nextLevelMerge[0];
392 (*this) *= 1 / static_cast<double>(to_average.size());
393 }
394
401 double distance(const Persistence_landscape& second, double power = 1) const {
402 if (power < std::numeric_limits<double>::max()) {
403 return compute_distance_of_landscapes(*this, second, power);
404 } else {
405 return compute_max_norm_distance_of_landscapes(*this, second);
406 }
407 }
408
414 double compute_scalar_product(const Persistence_landscape& second) const {
415 return compute_inner_product((*this), second);
416 }
417 // end of implementation of functions needed for concepts.
418
423 std::pair<double, double> get_y_range(size_t level = 0) const {
424 std::pair<double, double> result;
425 if (level < this->land.size()) {
426 double maxx = this->compute_maximum();
427 double minn = this->compute_minimum();
428 result = std::make_pair(minn, maxx);
429 } else {
430 result = std::make_pair(0, 0);
431 }
432 return result;
433 }
434
435 // a function used to create a gnuplot script for visualization of landscapes
436 void plot(const char* filename, double xRangeBegin = std::numeric_limits<double>::max(),
437 double xRangeEnd = std::numeric_limits<double>::max(),
438 double yRangeBegin = std::numeric_limits<double>::max(),
439 double yRangeEnd = std::numeric_limits<double>::max(), int from = std::numeric_limits<int>::max(),
440 int to = std::numeric_limits<int>::max());
441
442 protected:
443 std::vector<std::vector<std::pair<double, double> > > land;
444 size_t number_of_functions_for_vectorization;
445 size_t number_of_functions_for_projections_to_reals;
446
447 void construct_persistence_landscape_from_barcode(const std::vector<std::pair<double, double> >& p,
448 size_t number_of_levels = std::numeric_limits<size_t>::max());
449 Persistence_landscape multiply_lanscape_by_real_number_not_overwrite(double x) const;
450 void multiply_lanscape_by_real_number_overwrite(double x);
451 friend double compute_maximal_distance_non_symmetric(const Persistence_landscape& pl1,
452 const Persistence_landscape& pl2);
453
454 void set_up_numbers_of_functions_for_vectorization_and_projections_to_reals() {
455 // warning, this function can be only called after filling in the intervals vector.
456 this->number_of_functions_for_vectorization = this->land.size();
457 this->number_of_functions_for_projections_to_reals = this->land.size();
458 }
459};
460
461Persistence_landscape::Persistence_landscape(const char* filename, size_t dimension, size_t number_of_levels) {
462 std::vector<std::pair<double, double> > barcode;
463 if (dimension < std::numeric_limits<double>::max()) {
464 barcode = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
465 } else {
466 barcode = read_persistence_intervals_in_one_dimension_from_file(filename);
467 }
468 this->construct_persistence_landscape_from_barcode(barcode, number_of_levels);
469 this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
470}
471
472bool operatorEqualDbg = false;
474 if (this->land.size() != rhs.land.size()) {
475 if (operatorEqualDbg) std::clog << "1\n";
476 return false;
477 }
478 for (size_t level = 0; level != this->land.size(); ++level) {
479 if (this->land[level].size() != rhs.land[level].size()) {
480 if (operatorEqualDbg) std::clog << "this->land[level].size() : " << this->land[level].size() << "\n";
481 if (operatorEqualDbg) std::clog << "rhs.land[level].size() : " << rhs.land[level].size() << "\n";
482 if (operatorEqualDbg) std::clog << "2\n";
483 return false;
484 }
485 for (size_t i = 0; i != this->land[level].size(); ++i) {
486 if (!(almost_equal(this->land[level][i].first, rhs.land[level][i].first) &&
487 almost_equal(this->land[level][i].second, rhs.land[level][i].second))) {
488 if (operatorEqualDbg)
489 std::clog << "this->land[level][i] : " << this->land[level][i].first << " " << this->land[level][i].second
490 << "\n";
491 if (operatorEqualDbg)
492 std::clog << "rhs.land[level][i] : " << rhs.land[level][i].first << " " << rhs.land[level][i].second << "\n";
493 if (operatorEqualDbg) std::clog << "3\n";
494 return false;
495 }
496 }
497 }
498 return true;
499}
500
501Persistence_landscape::Persistence_landscape(const std::vector<std::pair<double, double> >& p,
502 size_t number_of_levels) {
503 this->construct_persistence_landscape_from_barcode(p, number_of_levels);
504 this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
505}
506
507void Persistence_landscape::construct_persistence_landscape_from_barcode(
508 const std::vector<std::pair<double, double> >& p, size_t number_of_levels) {
509 bool dbg = false;
510 if (dbg) {
511 std::clog << "Persistence_landscape::Persistence_landscape( const std::vector< std::pair< double , double > >& p )"
512 << std::endl;
513 }
514
515 // this is a general algorithm to construct persistence landscapes.
516 std::vector<std::pair<double, double> > bars;
517 bars.insert(bars.begin(), p.begin(), p.end());
518 std::sort(bars.begin(), bars.end(), compare_points_sorting);
519
520 if (dbg) {
521 std::clog << "Bars : \n";
522 for (size_t i = 0; i != bars.size(); ++i) {
523 std::clog << bars[i].first << " " << bars[i].second << "\n";
524 }
525 getchar();
526 }
527
528 std::vector<std::pair<double, double> > characteristicPoints(p.size());
529 for (size_t i = 0; i != bars.size(); ++i) {
530 characteristicPoints[i] =
531 std::make_pair((bars[i].first + bars[i].second) / 2.0, (bars[i].second - bars[i].first) / 2.0);
532 }
533 std::vector<std::vector<std::pair<double, double> > > Persistence_landscape;
534 size_t number_of_levels_in_the_landscape = 0;
535 while (!characteristicPoints.empty()) {
536 if (dbg) {
537 for (size_t i = 0; i != characteristicPoints.size(); ++i) {
538 std::clog << "(" << characteristicPoints[i].first << " " << characteristicPoints[i].second << ")\n";
539 }
540 std::cin.ignore();
541 }
542
543 std::vector<std::pair<double, double> > lambda_n;
544 lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
545 lambda_n.push_back(std::make_pair(minus_length(characteristicPoints[0]), 0));
546 lambda_n.push_back(characteristicPoints[0]);
547
548 if (dbg) {
549 std::clog << "1 Adding to lambda_n : (" << -std::numeric_limits<int>::max() << " " << 0 << ") , ("
550 << minus_length(characteristicPoints[0]) << " " << 0 << ") , (" << characteristicPoints[0].first << " "
551 << characteristicPoints[0].second << ") \n";
552 }
553
554 size_t i = 1;
555 std::vector<std::pair<double, double> > newCharacteristicPoints;
556 while (i < characteristicPoints.size()) {
557 size_t p = 1;
558 if ((minus_length(characteristicPoints[i]) >= minus_length(lambda_n[lambda_n.size() - 1])) &&
559 (birth_plus_deaths(characteristicPoints[i]) > birth_plus_deaths(lambda_n[lambda_n.size() - 1]))) {
560 if (minus_length(characteristicPoints[i]) < birth_plus_deaths(lambda_n[lambda_n.size() - 1])) {
561 std::pair<double, double> point = std::make_pair(
562 (minus_length(characteristicPoints[i]) + birth_plus_deaths(lambda_n[lambda_n.size() - 1])) / 2,
563 (birth_plus_deaths(lambda_n[lambda_n.size() - 1]) - minus_length(characteristicPoints[i])) / 2);
564 lambda_n.push_back(point);
565 if (dbg) {
566 std::clog << "2 Adding to lambda_n : (" << point.first << " " << point.second << ")\n";
567 }
568
569 if (dbg) {
570 std::clog << "characteristicPoints[i+p] : " << characteristicPoints[i + p].first << " "
571 << characteristicPoints[i + p].second << "\n";
572 std::clog << "point : " << point.first << " " << point.second << "\n";
573 getchar();
574 }
575
576 while ((i + p < characteristicPoints.size()) &&
577 (almost_equal(minus_length(point), minus_length(characteristicPoints[i + p]))) &&
578 (birth_plus_deaths(point) <= birth_plus_deaths(characteristicPoints[i + p]))) {
579 newCharacteristicPoints.push_back(characteristicPoints[i + p]);
580 if (dbg) {
581 std::clog << "3.5 Adding to newCharacteristicPoints : (" << characteristicPoints[i + p].first << " "
582 << characteristicPoints[i + p].second << ")\n";
583 getchar();
584 }
585 ++p;
586 }
587
588 newCharacteristicPoints.push_back(point);
589 if (dbg) {
590 std::clog << "4 Adding to newCharacteristicPoints : (" << point.first << " " << point.second << ")\n";
591 }
592
593 while ((i + p < characteristicPoints.size()) &&
594 (minus_length(point) <= minus_length(characteristicPoints[i + p])) &&
595 (birth_plus_deaths(point) >= birth_plus_deaths(characteristicPoints[i + p]))) {
596 newCharacteristicPoints.push_back(characteristicPoints[i + p]);
597 if (dbg) {
598 std::clog << "characteristicPoints[i+p] : " << characteristicPoints[i + p].first << " "
599 << characteristicPoints[i + p].second << "\n";
600 std::clog << "point : " << point.first << " " << point.second << "\n";
601 std::clog << "characteristicPoints[i+p] birth and death : " << minus_length(characteristicPoints[i + p])
602 << " , " << birth_plus_deaths(characteristicPoints[i + p]) << "\n";
603 std::clog << "point birth and death : " << minus_length(point) << " , " << birth_plus_deaths(point)
604 << "\n";
605
606 std::clog << "3 Adding to newCharacteristicPoints : (" << characteristicPoints[i + p].first << " "
607 << characteristicPoints[i + p].second << ")\n";
608 getchar();
609 }
610 ++p;
611 }
612
613 } else {
614 lambda_n.push_back(std::make_pair(birth_plus_deaths(lambda_n[lambda_n.size() - 1]), 0));
615 lambda_n.push_back(std::make_pair(minus_length(characteristicPoints[i]), 0));
616 if (dbg) {
617 std::clog << "5 Adding to lambda_n : (" << birth_plus_deaths(lambda_n[lambda_n.size() - 1]) << " " << 0
618 << ")\n";
619 std::clog << "5 Adding to lambda_n : (" << minus_length(characteristicPoints[i]) << " " << 0 << ")\n";
620 }
621 }
622 lambda_n.push_back(characteristicPoints[i]);
623 if (dbg) {
624 std::clog << "6 Adding to lambda_n : (" << characteristicPoints[i].first << " "
625 << characteristicPoints[i].second << ")\n";
626 }
627 } else {
628 newCharacteristicPoints.push_back(characteristicPoints[i]);
629 if (dbg) {
630 std::clog << "7 Adding to newCharacteristicPoints : (" << characteristicPoints[i].first << " "
631 << characteristicPoints[i].second << ")\n";
632 }
633 }
634 i = i + p;
635 }
636 lambda_n.push_back(std::make_pair(birth_plus_deaths(lambda_n[lambda_n.size() - 1]), 0));
637 lambda_n.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
638
639 characteristicPoints = newCharacteristicPoints;
640
641 lambda_n.erase(std::unique(lambda_n.begin(), lambda_n.end()), lambda_n.end());
642 this->land.push_back(lambda_n);
643
644 ++number_of_levels_in_the_landscape;
645 if (number_of_levels == number_of_levels_in_the_landscape) {
646 break;
647 }
648 }
649}
650
651// this function find maximum of lambda_n
652double Persistence_landscape::find_max(unsigned lambda) const {
653 if (this->land.size() < lambda) return 0;
654 double maximum = -std::numeric_limits<int>::max();
655 for (size_t i = 0; i != this->land[lambda].size(); ++i) {
656 if (this->land[lambda][i].second > maximum) maximum = this->land[lambda][i].second;
657 }
658 return maximum;
659}
660
662 double result = 0;
663 for (size_t i = 0; i != this->land.size(); ++i) {
664 for (size_t nr = 2; nr != this->land[i].size() - 1; ++nr) {
665 // it suffices to compute every planar integral and then sum them up for each lambda_n
666 result += 0.5 * (this->land[i][nr].first - this->land[i][nr - 1].first) *
667 (this->land[i][nr].second + this->land[i][nr - 1].second);
668 }
669 }
670 return result;
671}
672
674 double result = 0;
675 if (level >= this->land.size()) {
676 // this landscape function is constantly equal 0, so is the integral.
677 return result;
678 }
679 // also negative landscapes are assumed to be zero.
680 if (level < 0) return 0;
681
682 for (size_t nr = 2; nr != this->land[level].size() - 1; ++nr) {
683 // it suffices to compute every planar integral and then sum them up for each lambda_n
684 result += 0.5 * (this->land[level][nr].first - this->land[level][nr - 1].first) *
685 (this->land[level][nr].second + this->land[level][nr - 1].second);
686 }
687
688 return result;
689}
690
692 bool dbg = false;
693 double result = 0;
694 for (size_t i = 0; i != this->land.size(); ++i) {
695 for (size_t nr = 2; nr != this->land[i].size() - 1; ++nr) {
696 if (dbg) std::clog << "nr : " << nr << "\n";
697 // In this interval, the landscape has a form f(x) = ax+b. We want to compute integral of (ax+b)^p = 1/a *
698 // (ax+b)^{p+1}/(p+1)
699 std::pair<double, double> coef = compute_parameters_of_a_line(this->land[i][nr], this->land[i][nr - 1]);
700 double a = coef.first;
701 double b = coef.second;
702
703 if (dbg)
704 std::clog << "(" << this->land[i][nr].first << "," << this->land[i][nr].second << ") , "
705 << this->land[i][nr - 1].first << "," << this->land[i][nr].second << ")" << std::endl;
706 if (this->land[i][nr].first == this->land[i][nr - 1].first) continue;
707 if (a != 0) {
708 result += 1 / (a * (p + 1)) *
709 (pow((a * this->land[i][nr].first + b), p + 1) - pow((a * this->land[i][nr - 1].first + b), p + 1));
710 } else {
711 result += (this->land[i][nr].first - this->land[i][nr - 1].first) * (pow(this->land[i][nr].second, p));
712 }
713 if (dbg) {
714 std::clog << "a : " << a << " , b : " << b << std::endl;
715 std::clog << "result : " << result << std::endl;
716 }
717 }
718 }
719 return result;
720}
721
722// this is O(log(n)) algorithm, where n is number of points in this->land.
723double Persistence_landscape::compute_value_at_a_given_point(unsigned level, double x) const {
724 bool compute_value_at_a_given_pointDbg = false;
725 // in such a case lambda_level = 0.
726 if (level >= this->land.size()) return 0;
727
728 // we know that the points in this->land[level] are ordered according to x coordinate. Therefore, we can find the
729 // point by using bisection:
730 unsigned coordBegin = 1;
731 unsigned coordEnd = this->land[level].size() - 2;
732
733 if (compute_value_at_a_given_pointDbg) {
734 std::clog << "Here \n";
735 std::clog << "x : " << x << "\n";
736 std::clog << "this->land[level][coordBegin].first : " << this->land[level][coordBegin].first << "\n";
737 std::clog << "this->land[level][coordEnd].first : " << this->land[level][coordEnd].first << "\n";
738 }
739
740 // in this case x is outside the support of the landscape, therefore the value of the landscape is 0.
741 if (x <= this->land[level][coordBegin].first) return 0;
742 if (x >= this->land[level][coordEnd].first) return 0;
743
744 if (compute_value_at_a_given_pointDbg) std::clog << "Entering to the while loop \n";
745
746 while (coordBegin + 1 != coordEnd) {
747 if (compute_value_at_a_given_pointDbg) {
748 std::clog << "coordBegin : " << coordBegin << "\n";
749 std::clog << "coordEnd : " << coordEnd << "\n";
750 std::clog << "this->land[level][coordBegin].first : " << this->land[level][coordBegin].first << "\n";
751 std::clog << "this->land[level][coordEnd].first : " << this->land[level][coordEnd].first << "\n";
752 }
753
754 unsigned newCord = (unsigned)floor((coordEnd + coordBegin) / 2.0);
755
756 if (compute_value_at_a_given_pointDbg) {
757 std::clog << "newCord : " << newCord << "\n";
758 std::clog << "this->land[level][newCord].first : " << this->land[level][newCord].first << "\n";
759 std::cin.ignore();
760 }
761
762 if (this->land[level][newCord].first <= x) {
763 coordBegin = newCord;
764 if (this->land[level][newCord].first == x) return this->land[level][newCord].second;
765 } else {
766 coordEnd = newCord;
767 }
768 }
769
770 if (compute_value_at_a_given_pointDbg) {
771 std::clog << "x : " << x << " is between : " << this->land[level][coordBegin].first << " a "
772 << this->land[level][coordEnd].first << "\n";
773 std::clog << "the y coords are : " << this->land[level][coordBegin].second << " a "
774 << this->land[level][coordEnd].second << "\n";
775 std::clog << "coordBegin : " << coordBegin << "\n";
776 std::clog << "coordEnd : " << coordEnd << "\n";
777 std::cin.ignore();
778 }
779 return function_value(this->land[level][coordBegin], this->land[level][coordEnd], x);
780}
781
782std::ostream& operator<<(std::ostream& out, Persistence_landscape& land) {
783 for (size_t level = 0; level != land.land.size(); ++level) {
784 out << "Lambda_" << level << ":" << std::endl;
785 for (size_t i = 0; i != land.land[level].size(); ++i) {
786 if (land.land[level][i].first == -std::numeric_limits<int>::max()) {
787 out << "-inf";
788 } else {
789 if (land.land[level][i].first == std::numeric_limits<int>::max()) {
790 out << "+inf";
791 } else {
792 out << land.land[level][i].first;
793 }
794 }
795 out << " , " << land.land[level][i].second << std::endl;
796 }
797 }
798 return out;
799}
800
801void Persistence_landscape::multiply_lanscape_by_real_number_overwrite(double x) {
802 for (size_t dim = 0; dim != this->land.size(); ++dim) {
803 for (size_t i = 0; i != this->land[dim].size(); ++i) {
804 this->land[dim][i].second *= x;
805 }
806 }
807}
808
809bool AbsDbg = false;
812 for (size_t level = 0; level != this->land.size(); ++level) {
813 if (AbsDbg) {
814 std::clog << "level: " << level << std::endl;
815 }
816 std::vector<std::pair<double, double> > lambda_n;
817 lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
818 for (size_t i = 1; i != this->land[level].size(); ++i) {
819 if (AbsDbg) {
820 std::clog << "this->land[" << level << "][" << i << "] : " << this->land[level][i].first << " "
821 << this->land[level][i].second << std::endl;
822 }
823 // if a line segment between this->land[level][i-1] and this->land[level][i] crosses the x-axis, then we have to
824 // add one landscape point t o result
825 if ((this->land[level][i - 1].second) * (this->land[level][i].second) < 0) {
826 double zero =
827 find_zero_of_a_line_segment_between_those_two_points(this->land[level][i - 1], this->land[level][i]);
828
829 lambda_n.push_back(std::make_pair(zero, 0));
830 lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
831 if (AbsDbg) {
832 std::clog << "Adding pair : (" << zero << ",0)" << std::endl;
833 std::clog << "In the same step adding pair : (" << this->land[level][i].first << ","
834 << fabs(this->land[level][i].second) << ") " << std::endl;
835 std::cin.ignore();
836 }
837 } else {
838 lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
839 if (AbsDbg) {
840 std::clog << "Adding pair : (" << this->land[level][i].first << "," << fabs(this->land[level][i].second)
841 << ") " << std::endl;
842 std::cin.ignore();
843 }
844 }
845 }
846 result.land.push_back(lambda_n);
847 }
848 return result;
849}
850
851Persistence_landscape* Persistence_landscape::new_abs() {
852 Persistence_landscape* result = new Persistence_landscape(*this);
853 for (size_t level = 0; level != this->land.size(); ++level) {
854 if (AbsDbg) {
855 std::clog << "level: " << level << std::endl;
856 }
857 std::vector<std::pair<double, double> > lambda_n;
858 lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
859 for (size_t i = 1; i != this->land[level].size(); ++i) {
860 if (AbsDbg) {
861 std::clog << "this->land[" << level << "][" << i << "] : " << this->land[level][i].first << " "
862 << this->land[level][i].second << std::endl;
863 }
864 // if a line segment between this->land[level][i-1] and this->land[level][i] crosses the x-axis, then we have to
865 // add one landscape point t o result
866 if ((this->land[level][i - 1].second) * (this->land[level][i].second) < 0) {
867 double zero =
868 find_zero_of_a_line_segment_between_those_two_points(this->land[level][i - 1], this->land[level][i]);
869
870 lambda_n.push_back(std::make_pair(zero, 0));
871 lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
872 if (AbsDbg) {
873 std::clog << "Adding pair : (" << zero << ",0)" << std::endl;
874 std::clog << "In the same step adding pair : (" << this->land[level][i].first << ","
875 << fabs(this->land[level][i].second) << ") " << std::endl;
876 std::cin.ignore();
877 }
878 } else {
879 lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
880 if (AbsDbg) {
881 std::clog << "Adding pair : (" << this->land[level][i].first << "," << fabs(this->land[level][i].second)
882 << ") " << std::endl;
883 std::cin.ignore();
884 }
885 }
886 }
887 result->land.push_back(lambda_n);
888 }
889 return result;
890}
891
892Persistence_landscape Persistence_landscape::multiply_lanscape_by_real_number_not_overwrite(double x) const {
893 std::vector<std::vector<std::pair<double, double> > > result(this->land.size());
894 for (size_t dim = 0; dim != this->land.size(); ++dim) {
895 std::vector<std::pair<double, double> > lambda_dim(this->land[dim].size());
896 for (size_t i = 0; i != this->land[dim].size(); ++i) {
897 lambda_dim[i] = std::make_pair(this->land[dim][i].first, x * this->land[dim][i].second);
898 }
899 result[dim] = lambda_dim;
900 }
902 // CHANGE
903 // res.land = result;
904 res.land.swap(result);
905 return res;
906} // multiply_lanscape_by_real_number_overwrite
907
908void Persistence_landscape::print_to_file(const char* filename) const {
909 std::ofstream write;
910 write.open(filename);
911 for (size_t dim = 0; dim != this->land.size(); ++dim) {
912 write << "#lambda_" << dim << std::endl;
913 for (size_t i = 1; i != this->land[dim].size() - 1; ++i) {
914 write << this->land[dim][i].first << " " << this->land[dim][i].second << std::endl;
915 }
916 }
917 write.close();
918}
919
921 bool dbg = false;
922 // removing the current content of the persistence landscape.
923 this->land.clear();
924
925 // this constructor reads persistence landscape form a file. This file have to be created by this software before head
926 std::ifstream in;
927 in.open(filename);
928 if (!in.good()) {
929 std::cerr << "The file : " << filename << " do not exist. The program will now terminate \n";
930 throw "The persistence landscape file do not exist. The program will now terminate \n";
931 }
932
933 std::string line;
934 std::vector<std::pair<double, double> > landscapeAtThisLevel;
935
936 bool isThisAFirsLine = true;
937 while (in.good()) {
938 getline(in, line);
939 if (!(line.length() == 0 || line[0] == '#')) {
940 std::stringstream lineSS;
941 lineSS << line;
942 double beginn, endd;
943 lineSS >> beginn;
944 lineSS >> endd;
945 landscapeAtThisLevel.push_back(std::make_pair(beginn, endd));
946 if (dbg) {
947 std::clog << "Reading a point : " << beginn << " , " << endd << std::endl;
948 }
949 } else {
950 if (dbg) {
951 std::clog << "IGNORE LINE\n";
952 getchar();
953 }
954 if (!isThisAFirsLine) {
955 landscapeAtThisLevel.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
956 this->land.push_back(landscapeAtThisLevel);
957 std::vector<std::pair<double, double> > newLevelOdLandscape;
958 landscapeAtThisLevel.swap(newLevelOdLandscape);
959 }
960 landscapeAtThisLevel.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
961 isThisAFirsLine = false;
962 }
963 }
964 if (landscapeAtThisLevel.size() > 1) {
965 // seems that the last line of the file is not finished with the newline sign. We need to put what we have in
966 // landscapeAtThisLevel to the constructed landscape.
967 landscapeAtThisLevel.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
968 this->land.push_back(landscapeAtThisLevel);
969 }
970
971 in.close();
972}
973
974template <typename T>
975Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
976 const Persistence_landscape& land2) {
977 bool operation_on_pair_of_landscapesDBG = false;
978 if (operation_on_pair_of_landscapesDBG) {
979 std::clog << "operation_on_pair_of_landscapes\n";
980 std::cin.ignore();
981 }
983 std::vector<std::vector<std::pair<double, double> > > land(std::max(land1.land.size(), land2.land.size()));
984 result.land = land;
985 T oper;
986
987 if (operation_on_pair_of_landscapesDBG) {
988 for (size_t i = 0; i != std::min(land1.land.size(), land2.land.size()); ++i) {
989 std::clog << "land1.land[" << i << "].size() : " << land1.land[i].size() << std::endl;
990 std::clog << "land2.land[" << i << "].size() : " << land2.land[i].size() << std::endl;
991 }
992 getchar();
993 }
994
995 for (size_t i = 0; i != std::min(land1.land.size(), land2.land.size()); ++i) {
996 std::vector<std::pair<double, double> > lambda_n;
997 size_t p = 0;
998 size_t q = 0;
999 while ((p + 1 < land1.land[i].size()) && (q + 1 < land2.land[i].size())) {
1000 if (operation_on_pair_of_landscapesDBG) {
1001 std::clog << "p : " << p << "\n";
1002 std::clog << "q : " << q << "\n";
1003 std::clog << "land1.land.size() : " << land1.land.size() << std::endl;
1004 std::clog << "land2.land.size() : " << land2.land.size() << std::endl;
1005 std::clog << "land1.land[" << i << "].size() : " << land1.land[i].size() << std::endl;
1006 std::clog << "land2.land[" << i << "].size() : " << land2.land[i].size() << std::endl;
1007 std::clog << "land1.land[i][p].first : " << land1.land[i][p].first << "\n";
1008 std::clog << "land2.land[i][q].first : " << land2.land[i][q].first << "\n";
1009 }
1010
1011 if (land1.land[i][p].first < land2.land[i][q].first) {
1012 if (operation_on_pair_of_landscapesDBG) {
1013 std::clog << "first \n";
1014 std::clog << " function_value(land2.land[i][q-1],land2.land[i][q],land1.land[i][p].first) : "
1015 << function_value(land2.land[i][q - 1], land2.land[i][q], land1.land[i][p].first) << "\n";
1016 }
1017 lambda_n.push_back(
1018 std::make_pair(land1.land[i][p].first,
1019 oper(static_cast<double>(land1.land[i][p].second),
1020 function_value(land2.land[i][q - 1], land2.land[i][q], land1.land[i][p].first))));
1021 ++p;
1022 continue;
1023 }
1024 if (land1.land[i][p].first > land2.land[i][q].first) {
1025 if (operation_on_pair_of_landscapesDBG) {
1026 std::clog << "Second \n";
1027 std::clog << "function_value(" << land1.land[i][p - 1].first << " " << land1.land[i][p - 1].second << " ,"
1028 << land1.land[i][p].first << " " << land1.land[i][p].second << ", " << land2.land[i][q].first
1029 << " ) : " << function_value(land1.land[i][p - 1], land1.land[i][p - 1], land2.land[i][q].first)
1030 << "\n";
1031 std::clog << "oper( " << function_value(land1.land[i][p], land1.land[i][p - 1], land2.land[i][q].first) << ","
1032 << land2.land[i][q].second << " : "
1033 << oper(land2.land[i][q].second,
1034 function_value(land1.land[i][p], land1.land[i][p - 1], land2.land[i][q].first))
1035 << "\n";
1036 }
1037 lambda_n.push_back(std::make_pair(
1038 land2.land[i][q].first, oper(function_value(land1.land[i][p], land1.land[i][p - 1], land2.land[i][q].first),
1039 land2.land[i][q].second)));
1040 ++q;
1041 continue;
1042 }
1043 if (land1.land[i][p].first == land2.land[i][q].first) {
1044 if (operation_on_pair_of_landscapesDBG) std::clog << "Third \n";
1045 lambda_n.push_back(
1046 std::make_pair(land2.land[i][q].first, oper(land1.land[i][p].second, land2.land[i][q].second)));
1047 ++p;
1048 ++q;
1049 }
1050 if (operation_on_pair_of_landscapesDBG) {
1051 std::clog << "Next iteration \n";
1052 }
1053 }
1054 while ((p + 1 < land1.land[i].size()) && (q + 1 >= land2.land[i].size())) {
1055 if (operation_on_pair_of_landscapesDBG) {
1056 std::clog << "New point : " << land1.land[i][p].first
1057 << " oper(land1.land[i][p].second,0) : " << oper(land1.land[i][p].second, 0) << std::endl;
1058 }
1059 lambda_n.push_back(std::make_pair(land1.land[i][p].first, oper(land1.land[i][p].second, 0)));
1060 ++p;
1061 }
1062 while ((p + 1 >= land1.land[i].size()) && (q + 1 < land2.land[i].size())) {
1063 if (operation_on_pair_of_landscapesDBG) {
1064 std::clog << "New point : " << land2.land[i][q].first
1065 << " oper(0,land2.land[i][q].second) : " << oper(0, land2.land[i][q].second) << std::endl;
1066 }
1067 lambda_n.push_back(std::make_pair(land2.land[i][q].first, oper(0, land2.land[i][q].second)));
1068 ++q;
1069 }
1070 lambda_n.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
1071 // CHANGE
1072 // result.land[i] = lambda_n;
1073 result.land[i].swap(lambda_n);
1074 }
1075 if (land1.land.size() > std::min(land1.land.size(), land2.land.size())) {
1076 if (operation_on_pair_of_landscapesDBG) {
1077 std::clog << "land1.land.size() > std::min( land1.land.size() , land2.land.size() )" << std::endl;
1078 }
1079 for (size_t i = std::min(land1.land.size(), land2.land.size()); i != std::max(land1.land.size(), land2.land.size());
1080 ++i) {
1081 std::vector<std::pair<double, double> > lambda_n(land1.land[i]);
1082 for (size_t nr = 0; nr != land1.land[i].size(); ++nr) {
1083 lambda_n[nr] = std::make_pair(land1.land[i][nr].first, oper(land1.land[i][nr].second, 0));
1084 }
1085 // CHANGE
1086 // result.land[i] = lambda_n;
1087 result.land[i].swap(lambda_n);
1088 }
1089 }
1090 if (land2.land.size() > std::min(land1.land.size(), land2.land.size())) {
1091 if (operation_on_pair_of_landscapesDBG) {
1092 std::clog << "( land2.land.size() > std::min( land1.land.size() , land2.land.size() ) ) " << std::endl;
1093 }
1094 for (size_t i = std::min(land1.land.size(), land2.land.size()); i != std::max(land1.land.size(), land2.land.size());
1095 ++i) {
1096 std::vector<std::pair<double, double> > lambda_n(land2.land[i]);
1097 for (size_t nr = 0; nr != land2.land[i].size(); ++nr) {
1098 lambda_n[nr] = std::make_pair(land2.land[i][nr].first, oper(0, land2.land[i][nr].second));
1099 }
1100 // CHANGE
1101 // result.land[i] = lambda_n;
1102 result.land[i].swap(lambda_n);
1103 }
1104 }
1105 if (operation_on_pair_of_landscapesDBG) {
1106 std::clog << "operation_on_pair_of_landscapes END\n";
1107 std::cin.ignore();
1108 }
1109 return result;
1110} // operation_on_pair_of_landscapes
1111
1112double compute_maximal_distance_non_symmetric(const Persistence_landscape& pl1, const Persistence_landscape& pl2) {
1113 bool dbg = false;
1114 if (dbg) std::clog << " compute_maximal_distance_non_symmetric \n";
1115 // this distance is not symmetric. It compute ONLY distance between inflection points of pl1 and pl2.
1116 double maxDist = 0;
1117 size_t minimalNumberOfLevels = std::min(pl1.land.size(), pl2.land.size());
1118 for (size_t level = 0; level != minimalNumberOfLevels; ++level) {
1119 if (dbg) {
1120 std::clog << "Level : " << level << std::endl;
1121 std::clog << "PL1 : \n";
1122 for (size_t i = 0; i != pl1.land[level].size(); ++i) {
1123 std::clog << "(" << pl1.land[level][i].first << "," << pl1.land[level][i].second << ") \n";
1124 }
1125 std::clog << "PL2 : \n";
1126 for (size_t i = 0; i != pl2.land[level].size(); ++i) {
1127 std::clog << "(" << pl2.land[level][i].first << "," << pl2.land[level][i].second << ") \n";
1128 }
1129 std::cin.ignore();
1130 }
1131
1132 int p2Count = 0;
1133 // In this case, I consider points at the infinity
1134 for (size_t i = 1; i != pl1.land[level].size() - 1; ++i) {
1135 while (true) {
1136 if ((pl1.land[level][i].first >= pl2.land[level][p2Count].first) &&
1137 (pl1.land[level][i].first <= pl2.land[level][p2Count + 1].first))
1138 break;
1139 p2Count++;
1140 }
1141 double val =
1142 fabs(function_value(pl2.land[level][p2Count], pl2.land[level][p2Count + 1], pl1.land[level][i].first) -
1143 pl1.land[level][i].second);
1144 if (maxDist <= val) maxDist = val;
1145
1146 if (dbg) {
1147 std::clog << pl1.land[level][i].first << "in [" << pl2.land[level][p2Count].first << ","
1148 << pl2.land[level][p2Count + 1].first << "] \n";
1149 std::clog << "pl1[level][i].second : " << pl1.land[level][i].second << std::endl;
1150 std::clog << "function_value( pl2[level][p2Count] , pl2[level][p2Count+1] , pl1[level][i].first ) : "
1151 << function_value(pl2.land[level][p2Count], pl2.land[level][p2Count + 1], pl1.land[level][i].first)
1152 << std::endl;
1153 std::clog << "val : " << val << std::endl;
1154 std::cin.ignore();
1155 }
1156 }
1157 }
1158
1159 if (dbg) std::clog << "minimalNumberOfLevels : " << minimalNumberOfLevels << std::endl;
1160
1161 if (minimalNumberOfLevels < pl1.land.size()) {
1162 for (size_t level = minimalNumberOfLevels; level != pl1.land.size(); ++level) {
1163 for (size_t i = 0; i != pl1.land[level].size(); ++i) {
1164 if (dbg) std::clog << "pl1[level][i].second : " << pl1.land[level][i].second << std::endl;
1165 if (maxDist < pl1.land[level][i].second) maxDist = pl1.land[level][i].second;
1166 }
1167 }
1168 }
1169 return maxDist;
1170}
1171
1172double compute_distance_of_landscapes(const Persistence_landscape& first, const Persistence_landscape& second,
1173 double p) {
1174 bool dbg = false;
1175 // This is what we want to compute: (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p). We will do it one step at a
1176 // time:
1177
1178 // first-second :
1179 Persistence_landscape lan = first - second;
1180
1181 //| first-second |:
1182 lan = lan.abs();
1183
1184 if (dbg) {
1185 std::clog << "Abs of difference ; " << lan << std::endl;
1186 getchar();
1187 }
1188
1189 if (p < std::numeric_limits<double>::max()) {
1190 // \int_{- \infty}^{+\infty}| first-second |^p
1191 double result;
1192 if (p != 1) {
1193 if (dbg) std::clog << "Power != 1, compute integral to the power p\n";
1194 result = lan.compute_integral_of_landscape(p);
1195 } else {
1196 if (dbg) std::clog << "Power = 1, compute integral \n";
1197 result = lan.compute_integral_of_landscape();
1198 }
1199 // (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p)
1200 return pow(result, 1.0 / p);
1201 } else {
1202 // p == infty
1203 if (dbg) std::clog << "Power = infty, compute maximum \n";
1204 return lan.compute_maximum();
1205 }
1206}
1207
1208double compute_max_norm_distance_of_landscapes(const Persistence_landscape& first,
1209 const Persistence_landscape& second) {
1210 return std::max(compute_maximal_distance_non_symmetric(first, second),
1211 compute_maximal_distance_non_symmetric(second, first));
1212}
1213
1214bool comparePairsForMerging(std::pair<double, unsigned> first, std::pair<double, unsigned> second) {
1215 return (first.first < second.first);
1216}
1217
1218double compute_inner_product(const Persistence_landscape& l1, const Persistence_landscape& l2) {
1219 bool dbg = false;
1220 double result = 0;
1221
1222 for (size_t level = 0; level != std::min(l1.size(), l2.size()); ++level) {
1223 if (dbg) {
1224 std::clog << "Computing inner product for a level : " << level << std::endl;
1225 getchar();
1226 }
1227 auto&& l1_land_level = l1.land[level];
1228 auto&& l2_land_level = l2.land[level];
1229
1230 if (l1_land_level.size() * l2_land_level.size() == 0) continue;
1231
1232 // endpoints of the interval on which we will compute the inner product of two locally linear functions:
1233 double x1 = -std::numeric_limits<int>::max();
1234 double x2;
1235 if (l1_land_level[1].first < l2_land_level[1].first) {
1236 x2 = l1_land_level[1].first;
1237 } else {
1238 x2 = l2_land_level[1].first;
1239 }
1240
1241 // iterators for the landscapes l1 and l2
1242 size_t l1It = 0;
1243 size_t l2It = 0;
1244
1245 while ((l1It < l1_land_level.size() - 1) && (l2It < l2_land_level.size() - 1)) {
1246 // compute the value of a inner product on a interval [x1,x2]
1247
1248 double a, b, c, d;
1249
1250 if (l1_land_level[l1It + 1].first != l1_land_level[l1It].first) {
1251 a = (l1_land_level[l1It + 1].second - l1_land_level[l1It].second) /
1252 (l1_land_level[l1It + 1].first - l1_land_level[l1It].first);
1253 } else {
1254 a = 0;
1255 }
1256 b = l1_land_level[l1It].second - a * l1_land_level[l1It].first;
1257 if (l2_land_level[l2It + 1].first != l2_land_level[l2It].first) {
1258 c = (l2_land_level[l2It + 1].second - l2_land_level[l2It].second) /
1259 (l2_land_level[l2It + 1].first - l2_land_level[l2It].first);
1260 } else {
1261 c = 0;
1262 }
1263 d = l2_land_level[l2It].second - c * l2_land_level[l2It].first;
1264
1265 double contributionFromThisPart = (a * c * x2 * x2 * x2 / 3 + (a * d + b * c) * x2 * x2 / 2 + b * d * x2) -
1266 (a * c * x1 * x1 * x1 / 3 + (a * d + b * c) * x1 * x1 / 2 + b * d * x1);
1267
1268 result += contributionFromThisPart;
1269
1270 if (dbg) {
1271 std::clog << "[l1_land_level[l1It].first,l1_land_level[l1It+1].first] : " << l1_land_level[l1It].first
1272 << " , " << l1_land_level[l1It + 1].first << std::endl;
1273 std::clog << "[l2_land_level[l2It].first,l2_land_level[l2It+1].first] : " << l2_land_level[l2It].first
1274 << " , " << l2_land_level[l2It + 1].first << std::endl;
1275 std::clog << "a : " << a << ", b : " << b << " , c: " << c << ", d : " << d << std::endl;
1276 std::clog << "x1 : " << x1 << " , x2 : " << x2 << std::endl;
1277 std::clog << "contributionFromThisPart : " << contributionFromThisPart << std::endl;
1278 std::clog << "result : " << result << std::endl;
1279 getchar();
1280 }
1281
1282 // we have two intervals in which functions are constant:
1283 // [l1_land_level[l1It].first , l1_land_level[l1It+1].first]
1284 // and
1285 // [l2_land_level[l2It].first , l2_land_level[l2It+1].first]
1286 // We also have an interval [x1,x2]. Since the intervals in the landscapes cover the whole R, then it is clear
1287 // that x2
1288 // is either l1_land_level[l1It+1].first of l2_land_level[l2It+1].first or both. Lets test it.
1289 if (x2 == l1_land_level[l1It + 1].first) {
1290 if (x2 == l2_land_level[l2It + 1].first) {
1291 // in this case, we increment both:
1292 ++l2It;
1293 if (dbg) {
1294 std::clog << "Incrementing both \n";
1295 }
1296 } else {
1297 if (dbg) {
1298 std::clog << "Incrementing first \n";
1299 }
1300 }
1301 ++l1It;
1302 } else {
1303 // in this case we increment l2It
1304 ++l2It;
1305 if (dbg) {
1306 std::clog << "Incrementing second \n";
1307 }
1308 }
1309
1310 if ( l1It + 1 >= l1_land_level.size() )break;
1311 if ( l2It + 1 >= l2_land_level.size() )break;
1312
1313 // Now, we shift x1 and x2:
1314 x1 = x2;
1315 if (l1_land_level[l1It + 1].first < l2_land_level[l2It + 1].first) {
1316 x2 = l1_land_level[l1It + 1].first;
1317 } else {
1318 x2 = l2_land_level[l2It + 1].first;
1319 }
1320 }
1321 }
1322 return result;
1323}
1324
1325void Persistence_landscape::plot(const char* filename, double xRangeBegin, double xRangeEnd, double yRangeBegin,
1326 double yRangeEnd, int from, int to) {
1327 // this program create a gnuplot script file that allows to plot persistence diagram.
1328 std::ofstream out;
1329
1330 std::ostringstream gnuplot_script;
1331 gnuplot_script << filename << "_GnuplotScript";
1332 out.open(gnuplot_script.str().c_str());
1333
1334 if ((xRangeBegin != std::numeric_limits<double>::max()) || (xRangeEnd != std::numeric_limits<double>::max()) ||
1335 (yRangeBegin != std::numeric_limits<double>::max()) || (yRangeEnd != std::numeric_limits<double>::max())) {
1336 out << "set xrange [" << xRangeBegin << " : " << xRangeEnd << "]" << std::endl;
1337 out << "set yrange [" << yRangeBegin << " : " << yRangeEnd << "]" << std::endl;
1338 }
1339
1340 if (from == std::numeric_limits<int>::max()) {
1341 from = 0;
1342 }
1343 if (to == std::numeric_limits<int>::max()) {
1344 to = this->land.size();
1345 }
1346
1347 out << "plot ";
1348 for (size_t lambda = std::min((size_t)from, this->land.size()); lambda != std::min((size_t)to, this->land.size());
1349 ++lambda) {
1350 // out << " '-' using 1:2 title 'l" << lambda << "' with lp";
1351 out << " '-' using 1:2 notitle with lp";
1352 if (lambda + 1 != std::min((size_t)to, this->land.size())) {
1353 out << ", \\";
1354 }
1355 out << std::endl;
1356 }
1357
1358 for (size_t lambda = std::min((size_t)from, this->land.size()); lambda != std::min((size_t)to, this->land.size());
1359 ++lambda) {
1360 for (size_t i = 1; i != this->land[lambda].size() - 1; ++i) {
1361 out << this->land[lambda][i].first << " " << this->land[lambda][i].second << std::endl;
1362 }
1363 out << "EOF" << std::endl;
1364 }
1365 std::clog << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
1366 << gnuplot_script.str().c_str() << "\'\"" << std::endl;
1367}
1368
1369} // namespace Persistence_representations
1370} // namespace Gudhi
1371
1372#endif // PERSISTENCE_LANDSCAPE_H_
A class implementing persistence landscapes data structures.
Definition: Persistence_landscape.h:60
friend double compute_inner_product(const Persistence_landscape &l1, const Persistence_landscape &l2)
Definition: Persistence_landscape.h:1218
bool operator==(const Persistence_landscape &rhs) const
Definition: Persistence_landscape.h:473
friend double compute_distance_of_landscapes(const Persistence_landscape &first, const Persistence_landscape &second, double p)
Definition: Persistence_landscape.h:1172
friend Persistence_landscape operator+(const Persistence_landscape &first, const Persistence_landscape &second)
Definition: Persistence_landscape.h:145
size_t number_of_projections_to_R() const
Definition: Persistence_landscape.h:314
double compute_scalar_product(const Persistence_landscape &second) const
Definition: Persistence_landscape.h:414
friend Persistence_landscape operator-(const Persistence_landscape &first, const Persistence_landscape &second)
Definition: Persistence_landscape.h:152
friend double compute_max_norm_distance_of_landscapes(const Persistence_landscape &first, const Persistence_landscape &second)
Definition: Persistence_landscape.h:1208
size_t number_of_vectorize_functions() const
Definition: Persistence_landscape.h:336
Persistence_landscape abs()
Definition: Persistence_landscape.h:810
friend Persistence_landscape add_two_landscapes(const Persistence_landscape &land1, const Persistence_landscape &land2)
Definition: Persistence_landscape.h:129
double find_max(unsigned lambda) const
Definition: Persistence_landscape.h:652
double compute_integral_of_a_level_of_a_landscape(size_t level) const
Definition: Persistence_landscape.h:673
friend Persistence_landscape subtract_two_landscapes(const Persistence_landscape &land1, const Persistence_landscape &land2)
Definition: Persistence_landscape.h:137
double compute_integral_of_landscape() const
Definition: Persistence_landscape.h:661
Persistence_landscape()
Definition: Persistence_landscape.h:65
Persistence_landscape operator-=(const Persistence_landscape &rhs)
Definition: Persistence_landscape.h:181
double distance(const Persistence_landscape &second, double power=1) const
Definition: Persistence_landscape.h:401
Persistence_landscape operator+=(const Persistence_landscape &rhs)
Definition: Persistence_landscape.h:173
double compute_value_at_a_given_point(unsigned level, double x) const
Definition: Persistence_landscape.h:723
double project_to_R(int number_of_function) const
Definition: Persistence_landscape.h:306
Persistence_landscape operator/=(double x)
Definition: Persistence_landscape.h:198
friend Persistence_landscape operator*(const Persistence_landscape &first, double con)
Definition: Persistence_landscape.h:159
std::vector< double > vectorize(int number_of_function) const
Definition: Persistence_landscape.h:320
double compute_maximum() const
Definition: Persistence_landscape.h:217
std::pair< double, double > get_y_range(size_t level=0) const
Definition: Persistence_landscape.h:423
void compute_average(const std::vector< Persistence_landscape * > &to_average)
Definition: Persistence_landscape.h:342
Persistence_landscape operator*=(double x)
Definition: Persistence_landscape.h:190
void print_to_file(const char *filename) const
Definition: Persistence_landscape.h:908
double operator()(unsigned level, double x) const
Definition: Persistence_landscape.h:257
friend Persistence_landscape operator*(double con, const Persistence_landscape &first)
Definition: Persistence_landscape.h:166
friend std::ostream & operator<<(std::ostream &out, Persistence_landscape &land)
Definition: Persistence_landscape.h:782
size_t size() const
Definition: Persistence_landscape.h:284
bool operator!=(const Persistence_landscape &rhs) const
Definition: Persistence_landscape.h:212
void load_landscape_from_file(const char *filename)
Definition: Persistence_landscape.h:920