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 * - 2025/06 Hannah Schreiber: Various small bug fixes (missing `inline`s, `DEBUG_TRACES`s etc.)
9 * - YYYY/MM Author: Description of the modification
10 */
11
12#ifndef PERSISTENCE_LANDSCAPE_H_
13#define PERSISTENCE_LANDSCAPE_H_
14
15// standard include
16#ifdef DEBUG_TRACES
17#include <iostream> // std::cerr, std::clog
18#endif
19#include <ostream> // std::ostream
20#include <fstream> // std::ofstream, std::ifstream
21#include <sstream> // std::stringstream, std::ostringstream
22#include <stdexcept> // std::invalid_argument
23#include <cstddef> // std::size_t
24#include <limits> // std::numeric_limits
25#include <algorithm> // std::sort
26#include <cmath> // std::min, std::max, std::pow, std::fabs
27#include <utility> // std::pair
28#include <string>
29#include <vector>
30
31// gudhi include
32#include <gudhi/read_persistence_from_file.h>
34#include <gudhi/Debug_utils.h>
35
36namespace Gudhi {
37namespace Persistence_representations {
38
39// pre declaration needed before C++20 for friends with templates defined inside a class
41template <typename Operation>
42Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
43 const Persistence_landscape& land2);
44
66{
67 public:
71 Persistence_landscape() { this->_set_up_numbers_of_functions_for_vectorization_and_projections_to_reals(); }
72
76 Persistence_landscape(const std::vector<std::pair<double, double> >& p,
77 std::size_t number_of_levels = std::numeric_limits<std::size_t>::max())
78 {
79 this->_construct_persistence_landscape_from_barcode(p, number_of_levels);
80 this->_set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
81 }
82
88 Persistence_landscape(const char* filename,
89 unsigned int dimension = std::numeric_limits<unsigned int>::max(),
90 std::size_t number_of_levels = std::numeric_limits<std::size_t>::max())
91 {
92 std::vector<std::pair<double, double> > barcode;
93 if (dimension < std::numeric_limits<unsigned int>::max()) {
94 barcode = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
95 } else {
97 }
98 this->_construct_persistence_landscape_from_barcode(barcode, number_of_levels);
99 this->_set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
100 }
101
105 void load_landscape_from_file(const char* filename);
106
110 void print_to_file(const char* filename) const;
111
116 double compute_integral_of_landscape() const;
117
121 double compute_integral_of_a_level_of_a_landscape(std::size_t level) const;
122
127 double compute_integral_of_landscape(double p) const; // this function compute integral of p-th power of landscape.
128
134 double compute_value_at_a_given_point(unsigned int level, double x) const;
135
141 friend std::ostream& operator<<(std::ostream& out, const Persistence_landscape& land)
142 {
143 for (std::size_t level = 0; level != land.land_.size(); ++level) {
144 out << "Lambda_" << level << ":" << std::endl;
145 for (std::size_t i = 0; i != land.land_[level].size(); ++i) {
146 if (land.land_[level][i].first == -std::numeric_limits<int>::max()) {
147 out << "-inf";
148 } else {
149 if (land.land_[level][i].first == std::numeric_limits<int>::max()) {
150 out << "+inf";
151 } else {
152 out << land.land_[level][i].first;
153 }
154 }
155 out << " , " << land.land_[level][i].second << std::endl;
156 }
157 }
158 return out;
159 }
160
161 template <typename Operation>
162 friend Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
163 const Persistence_landscape& land2)
164 {
165#ifdef DEBUG_TRACES
166 std::clog << "operation_on_pair_of_landscapes\n";
167#endif
169 std::vector<std::vector<std::pair<double, double> > > land(std::max(land1.land_.size(), land2.land_.size()));
170 result.land_ = land;
171 Operation oper;
172
173#ifdef DEBUG_TRACES
174 for (std::size_t i = 0; i != std::min(land1.land_.size(), land2.land_.size()); ++i) {
175 std::clog << "land1.land[" << i << "].size() : " << land1.land_[i].size() << std::endl;
176 std::clog << "land2.land[" << i << "].size() : " << land2.land_[i].size() << std::endl;
177 }
178#endif
179
180 for (std::size_t i = 0; i != std::min(land1.land_.size(), land2.land_.size()); ++i) {
181 std::vector<std::pair<double, double> > lambda_n;
182 std::size_t p = 0;
183 std::size_t q = 0;
184 while ((p + 1 < land1.land_[i].size()) && (q + 1 < land2.land_[i].size())) {
185#ifdef DEBUG_TRACES
186 std::clog << "p : " << p << "\n";
187 std::clog << "q : " << q << "\n";
188 std::clog << "land1.land.size() : " << land1.land_.size() << std::endl;
189 std::clog << "land2.land.size() : " << land2.land_.size() << std::endl;
190 std::clog << "land1.land[" << i << "].size() : " << land1.land_[i].size() << std::endl;
191 std::clog << "land2.land[" << i << "].size() : " << land2.land_[i].size() << std::endl;
192 std::clog << "land1.land[i][p].first : " << land1.land_[i][p].first << "\n";
193 std::clog << "land2.land[i][q].first : " << land2.land_[i][q].first << "\n";
194#endif
195
196 if (land1.land_[i][p].first < land2.land_[i][q].first) {
197#ifdef DEBUG_TRACES
198 std::clog << "first \n";
199 std::clog << " function_value(land2.land[i][q-1],land2.land[i][q],land1.land[i][p].first) : "
200 << function_value(land2.land_[i][q - 1], land2.land_[i][q], land1.land_[i][p].first) << "\n";
201#endif
202 lambda_n.push_back(
203 std::make_pair(land1.land_[i][p].first,
204 oper(static_cast<double>(land1.land_[i][p].second),
205 function_value(land2.land_[i][q - 1], land2.land_[i][q], land1.land_[i][p].first))));
206 ++p;
207 continue;
208 }
209 if (land1.land_[i][p].first > land2.land_[i][q].first) {
210#ifdef DEBUG_TRACES
211 std::clog << "Second \n";
212 std::clog << "function_value(" << land1.land_[i][p - 1].first << " " << land1.land_[i][p - 1].second << " ,"
213 << land1.land_[i][p].first << " " << land1.land_[i][p].second << ", " << land2.land_[i][q].first
214 << " ) : " << function_value(land1.land_[i][p - 1], land1.land_[i][p - 1], land2.land_[i][q].first)
215 << "\n";
216 std::clog << "oper( " << function_value(land1.land_[i][p], land1.land_[i][p - 1], land2.land_[i][q].first)
217 << "," << land2.land_[i][q].second << " : "
218 << oper(land2.land_[i][q].second,
219 function_value(land1.land_[i][p], land1.land_[i][p - 1], land2.land_[i][q].first))
220 << "\n";
221#endif
222 lambda_n.push_back(
223 std::make_pair(land2.land_[i][q].first,
224 oper(function_value(land1.land_[i][p], land1.land_[i][p - 1], land2.land_[i][q].first),
225 land2.land_[i][q].second)));
226 ++q;
227 continue;
228 }
229 if (land1.land_[i][p].first == land2.land_[i][q].first) {
230#ifdef DEBUG_TRACES
231 std::clog << "Third \n";
232#endif
233 lambda_n.push_back(
234 std::make_pair(land2.land_[i][q].first, oper(land1.land_[i][p].second, land2.land_[i][q].second)));
235 ++p;
236 ++q;
237 }
238#ifdef DEBUG_TRACES
239 std::clog << "Next iteration \n";
240#endif
241 }
242 while ((p + 1 < land1.land_[i].size()) && (q + 1 >= land2.land_[i].size())) {
243#ifdef DEBUG_TRACES
244 std::clog << "New point : " << land1.land_[i][p].first
245 << " oper(land1.land[i][p].second,0) : " << oper(land1.land_[i][p].second, 0) << std::endl;
246#endif
247 lambda_n.push_back(std::make_pair(land1.land_[i][p].first, oper(land1.land_[i][p].second, 0)));
248 ++p;
249 }
250 while ((p + 1 >= land1.land_[i].size()) && (q + 1 < land2.land_[i].size())) {
251#ifdef DEBUG_TRACES
252 std::clog << "New point : " << land2.land_[i][q].first
253 << " oper(0,land2.land[i][q].second) : " << oper(0, land2.land_[i][q].second) << std::endl;
254#endif
255 lambda_n.push_back(std::make_pair(land2.land_[i][q].first, oper(0, land2.land_[i][q].second)));
256 ++q;
257 }
258 lambda_n.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
259 // CHANGE
260 // result.land[i] = lambda_n;
261 result.land_[i].swap(lambda_n);
262 }
263 if (land1.land_.size() > std::min(land1.land_.size(), land2.land_.size())) {
264#ifdef DEBUG_TRACES
265 std::clog << "land1.land.size() > std::min( land1.land.size() , land2.land.size() )" << std::endl;
266#endif
267 for (std::size_t i = std::min(land1.land_.size(), land2.land_.size());
268 i != std::max(land1.land_.size(), land2.land_.size());
269 ++i) {
270 std::vector<std::pair<double, double> > lambda_n(land1.land_[i]);
271 for (std::size_t nr = 0; nr != land1.land_[i].size(); ++nr) {
272 lambda_n[nr] = std::make_pair(land1.land_[i][nr].first, oper(land1.land_[i][nr].second, 0));
273 }
274 // CHANGE
275 // result.land[i] = lambda_n;
276 result.land_[i].swap(lambda_n);
277 }
278 }
279 if (land2.land_.size() > std::min(land1.land_.size(), land2.land_.size())) {
280#ifdef DEBUG_TRACES
281 std::clog << "( land2.land.size() > std::min( land1.land.size() , land2.land.size() ) ) " << std::endl;
282#endif
283 for (std::size_t i = std::min(land1.land_.size(), land2.land_.size());
284 i != std::max(land1.land_.size(), land2.land_.size());
285 ++i) {
286 std::vector<std::pair<double, double> > lambda_n(land2.land_[i]);
287 for (std::size_t nr = 0; nr != land2.land_[i].size(); ++nr) {
288 lambda_n[nr] = std::make_pair(land2.land_[i][nr].first, oper(0, land2.land_[i][nr].second));
289 }
290 // CHANGE
291 // result.land[i] = lambda_n;
292 result.land_[i].swap(lambda_n);
293 }
294 }
295#ifdef DEBUG_TRACES
296 std::clog << "operation_on_pair_of_landscapes END\n";
297#endif
298 return result;
299 } // operation_on_pair_of_landscapes
300
301 // TODO: `add_two_landscapes` and `subtract_two_landscapes` do not seem to be used outside of resp.
302 // `operator+` and `operator-` and their doc is marked private. Are they really necessary?
303 // Can `operation_on_pair_of_landscapes` not be directly called in `operator+` and `operator-`?
304
309 const Persistence_landscape& land2)
310 {
311 return operation_on_pair_of_landscapes<std::plus<double> >(land1, land2);
312 }
313
318 const Persistence_landscape& land2)
319 {
320 return operation_on_pair_of_landscapes<std::minus<double> >(land1, land2);
321 }
322
327 {
328 return add_two_landscapes(first, second);
329 }
330
335 {
336 return subtract_two_landscapes(first, second);
337 }
338
343 {
344 return first._multiply_landscape_by_real_number_not_overwrite(con);
345 }
346
351 {
352 return first._multiply_landscape_by_real_number_not_overwrite(con);
353 }
354
359 {
360 *this = *this + rhs;
361 return *this;
362 }
363
368 {
369 *this = *this - rhs;
370 return *this;
371 }
372
378 {
379 *this = *this * x;
380 return *this;
381 }
382
387 {
388 if (x == 0) throw std::invalid_argument("In operator /=, division by 0.");
389 *this = *this * (1 / x);
390 return *this;
391 }
392
396 bool operator==(const Persistence_landscape& rhs) const;
397
401 bool operator!=(const Persistence_landscape& rhs) const { return !((*this) == rhs); }
402
406 double compute_maximum() const
407 {
408 double maxValue = 0;
409 if (this->land_.size()) {
410 maxValue = -std::numeric_limits<int>::max();
411 for (std::size_t i = 0; i != this->land_[0].size(); ++i) {
412 if (this->land_[0][i].second > maxValue) maxValue = this->land_[0][i].second;
413 }
414 }
415 return maxValue;
416 }
417
421 double compute_minimum() const
422 {
423 double minValue = 0;
424 if (this->land_.size()) {
425 minValue = std::numeric_limits<int>::max();
426 for (std::size_t i = 0; i != this->land_[0].size(); ++i) {
427 if (this->land_[0][i].second < minValue) minValue = this->land_[0][i].second;
428 }
429 }
430 return minValue;
431 }
432
436 double compute_norm_of_landscape(double i)
437 {
439 if (i < std::numeric_limits<double>::max()) {
440 return compute_distance_of_landscapes(*this, l, i);
441 } else {
443 }
444 }
445
449 double operator()(unsigned int level, double x) const { return this->compute_value_at_a_given_point(level, x); }
450
455 const Persistence_landscape& second)
456 {
457 return std::max(compute_maximal_distance_non_symmetric(first, second),
458 compute_maximal_distance_non_symmetric(second, first));
459 }
460
465 const Persistence_landscape& second,
466 double p)
467 {
468 // This is what we want to compute: (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p). We will do it one step at a
469 // time:
470
471 // first-second :
472 Persistence_landscape lan = first - second;
473
474 //| first-second |:
475 lan = lan.abs();
476
477#ifdef DEBUG_TRACES
478 std::clog << "Abs of difference ; " << lan << std::endl;
479#endif
480
481 if (p < std::numeric_limits<double>::max()) {
482 // \int_{- \infty}^{+\infty}| first-second |^p
483 double result;
484 if (p != 1) {
485#ifdef DEBUG_TRACES
486 std::clog << "Power != 1, compute integral to the power p\n";
487#endif
488 result = lan.compute_integral_of_landscape(p);
489 } else {
490#ifdef DEBUG_TRACES
491 std::clog << "Power = 1, compute integral \n";
492#endif
493 result = lan.compute_integral_of_landscape();
494 }
495 // (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p)
496 return std::pow(result, 1.0 / p);
497 } else {
498 // p == infty
499#ifdef DEBUG_TRACES
500 std::clog << "Power = infty, compute maximum \n";
501#endif
502 return lan.compute_maximum();
503 }
504 }
505
513
514 // TODO: it is public but not documented.
515 Persistence_landscape* new_abs();
516
520 std::size_t size() const { return this->land_.size(); }
521
525 double find_max(unsigned int lambda) const;
526
531 {
532 double result = 0;
533
534 for (std::size_t level = 0; level != std::min(l1.size(), l2.size()); ++level) {
535#ifdef DEBUG_TRACES
536 std::clog << "Computing inner product for a level : " << level << std::endl;
537#endif
538 auto&& l1_land_level = l1.land_[level];
539 auto&& l2_land_level = l2.land_[level];
540
541 if (l1_land_level.size() * l2_land_level.size() == 0) continue;
542
543 // endpoints of the interval on which we will compute the inner product of two locally linear functions:
544 double x1 = -std::numeric_limits<int>::max();
545 double x2;
546 if (l1_land_level[1].first < l2_land_level[1].first) {
547 x2 = l1_land_level[1].first;
548 } else {
549 x2 = l2_land_level[1].first;
550 }
551
552 // iterators for the landscapes l1 and l2
553 std::size_t l1It = 0;
554 std::size_t l2It = 0;
555
556 while ((l1It < l1_land_level.size() - 1) && (l2It < l2_land_level.size() - 1)) {
557 // compute the value of a inner product on a interval [x1,x2]
558
559 double a, b, c, d;
560
561 if (l1_land_level[l1It + 1].first != l1_land_level[l1It].first) {
562 a = (l1_land_level[l1It + 1].second - l1_land_level[l1It].second) /
563 (l1_land_level[l1It + 1].first - l1_land_level[l1It].first);
564 } else {
565 a = 0;
566 }
567 b = l1_land_level[l1It].second - a * l1_land_level[l1It].first;
568 if (l2_land_level[l2It + 1].first != l2_land_level[l2It].first) {
569 c = (l2_land_level[l2It + 1].second - l2_land_level[l2It].second) /
570 (l2_land_level[l2It + 1].first - l2_land_level[l2It].first);
571 } else {
572 c = 0;
573 }
574 d = l2_land_level[l2It].second - c * l2_land_level[l2It].first;
575
576 double contributionFromThisPart = (a * c * x2 * x2 * x2 / 3 + (a * d + b * c) * x2 * x2 / 2 + b * d * x2) -
577 (a * c * x1 * x1 * x1 / 3 + (a * d + b * c) * x1 * x1 / 2 + b * d * x1);
578
579 result += contributionFromThisPart;
580
581#ifdef DEBUG_TRACES
582 std::clog << "[l1_land_level[l1It].first,l1_land_level[l1It+1].first] : " << l1_land_level[l1It].first << " , "
583 << l1_land_level[l1It + 1].first << std::endl;
584 std::clog << "[l2_land_level[l2It].first,l2_land_level[l2It+1].first] : " << l2_land_level[l2It].first << " , "
585 << l2_land_level[l2It + 1].first << std::endl;
586 std::clog << "a : " << a << ", b : " << b << " , c: " << c << ", d : " << d << std::endl;
587 std::clog << "x1 : " << x1 << " , x2 : " << x2 << std::endl;
588 std::clog << "contributionFromThisPart : " << contributionFromThisPart << std::endl;
589 std::clog << "result : " << result << std::endl;
590#endif
591
592 // we have two intervals in which functions are constant:
593 // [l1_land_level[l1It].first , l1_land_level[l1It+1].first]
594 // and
595 // [l2_land_level[l2It].first , l2_land_level[l2It+1].first]
596 // We also have an interval [x1,x2]. Since the intervals in the landscapes cover the whole R, then it is clear
597 // that x2 is either l1_land_level[l1It+1].first of l2_land_level[l2It+1].first or both. Lets test it.
598 if (x2 == l1_land_level[l1It + 1].first) {
599 if (x2 == l2_land_level[l2It + 1].first) {
600 // in this case, we increment both:
601 ++l2It;
602#ifdef DEBUG_TRACES
603 std::clog << "Incrementing both \n";
604#endif
605 } else {
606#ifdef DEBUG_TRACES
607 std::clog << "Incrementing first \n";
608#endif
609 }
610 ++l1It;
611 } else {
612 // in this case we increment l2It
613 ++l2It;
614#ifdef DEBUG_TRACES
615 std::clog << "Incrementing second \n";
616#endif
617 }
618
619 if (l1It + 1 >= l1_land_level.size()) break;
620 if (l2It + 1 >= l2_land_level.size()) break;
621
622 // Now, we shift x1 and x2:
623 x1 = x2;
624 if (l1_land_level[l1It + 1].first < l2_land_level[l2It + 1].first) {
625 x2 = l1_land_level[l1It + 1].first;
626 } else {
627 x2 = l2_land_level[l2It + 1].first;
628 }
629 }
630 }
631 return result;
632 }
633
634 // Implementations of functions for various concepts.
635
643 double project_to_R(int number_of_function) const
644 {
645 return this->compute_integral_of_a_level_of_a_landscape((std::size_t)number_of_function);
646 }
647
652 std::size_t number_of_projections_to_R() const { return this->number_of_functions_for_projections_to_reals_; }
653
658 std::vector<double> vectorize(int number_of_function) const
659 {
660 // TODO(PD) think of something smarter over here
661 std::vector<double> v;
662 if (static_cast<std::size_t>(number_of_function) > this->land_.size()) {
663 return v;
664 }
665 v.reserve(this->land_[number_of_function].size());
666 for (std::size_t i = 0; i != this->land_[number_of_function].size(); ++i) {
667 v.push_back(this->land_[number_of_function][i].second);
668 }
669 return v;
670 }
671
676 std::size_t number_of_vectorize_functions() const { return this->number_of_functions_for_vectorization_; }
677
682 void compute_average(const std::vector<Persistence_landscape*>& to_average)
683 {
684#ifdef DEBUG_TRACES
685 std::clog << "to_average.size() : " << to_average.size() << std::endl;
686#endif
687
688 std::vector<Persistence_landscape*> nextLevelMerge(to_average.size());
689 for (std::size_t i = 0; i != to_average.size(); ++i) {
690 nextLevelMerge[i] = to_average[i];
691 }
692
693 // In the loop, we will create dynamically a number of intermediate complexes. We have to clean that up, but
694 // we cannot erase the initial landscapes we have to average. In this case, we simply check if the nextLevelMerge
695 // are the input landscapes or the ones created in that loop by using this extra variable.
696 bool is_this_first_level = true;
697
698 while (nextLevelMerge.size() != 1) {
699#ifdef DEBUG_TRACES
700 std::clog << "nextLevelMerge.size() : " << nextLevelMerge.size() << std::endl;
701#endif
702 std::vector<Persistence_landscape*> nextNextLevelMerge;
703 nextNextLevelMerge.reserve(to_average.size());
704 for (std::size_t i = 0; i < nextLevelMerge.size(); i = i + 2) {
705#ifdef DEBUG_TRACES
706 std::clog << "i : " << i << std::endl;
707#endif
709 if (i + 1 != nextLevelMerge.size()) {
710 (*l) = (*nextLevelMerge[i]) + (*nextLevelMerge[i + 1]);
711 } else {
712 (*l) = *nextLevelMerge[i];
713 }
714 nextNextLevelMerge.push_back(l);
715 }
716#ifdef DEBUG_TRACES
717 std::clog << "After this iteration \n";
718#endif
719
720 if (!is_this_first_level) {
721 // deallocate the memory if the vector nextLevelMerge do not consist of the initial landscapes
722 for (std::size_t i = 0; i != nextLevelMerge.size(); ++i) {
723 delete nextLevelMerge[i];
724 }
725 }
726 is_this_first_level = false;
727 nextLevelMerge.swap(nextNextLevelMerge);
728 }
729 (*this) = (*nextLevelMerge[0]);
730 if (!is_this_first_level) delete nextLevelMerge[0];
731 (*this) *= 1 / static_cast<double>(to_average.size());
732 }
733
740 double distance(const Persistence_landscape& second, double power = 1) const
741 {
742 if (power < std::numeric_limits<double>::max()) {
743 return compute_distance_of_landscapes(*this, second, power);
744 } else {
745 return compute_max_norm_distance_of_landscapes(*this, second);
746 }
747 }
748
755 {
756 return compute_inner_product((*this), second);
757 }
758
759 // end of implementation of functions needed for concepts.
760
765 std::pair<double, double> get_y_range(std::size_t level = 0) const
766 {
767 std::pair<double, double> result;
768 if (level < this->land_.size()) {
769 double maxx = this->compute_maximum();
770 double minn = this->compute_minimum();
771 result = std::make_pair(minn, maxx);
772 } else {
773 result = std::make_pair(0, 0);
774 }
775 return result;
776 }
777
778 // a function used to create a gnuplot script for visualization of landscapes
779 void plot(const char* filename,
780 double xRangeBegin = std::numeric_limits<double>::max(),
781 double xRangeEnd = std::numeric_limits<double>::max(),
782 double yRangeBegin = std::numeric_limits<double>::max(),
783 double yRangeEnd = std::numeric_limits<double>::max(),
784 int from = std::numeric_limits<int>::max(),
785 int to = std::numeric_limits<int>::max());
786
787 private:
788 friend double compute_maximal_distance_non_symmetric(const Persistence_landscape& pl1,
789 const Persistence_landscape& pl2)
790 {
791#ifdef DEBUG_TRACES
792 std::clog << " compute_maximal_distance_non_symmetric \n";
793#endif
794 // this distance is not symmetric. It compute ONLY distance between inflection points of pl1 and pl2.
795 double maxDist = 0;
796 std::size_t minimalNumberOfLevels = std::min(pl1.land_.size(), pl2.land_.size());
797 for (std::size_t level = 0; level != minimalNumberOfLevels; ++level) {
798#ifdef DEBUG_TRACES
799 std::clog << "Level : " << level << std::endl;
800 std::clog << "PL1 : \n";
801 for (std::size_t i = 0; i != pl1.land_[level].size(); ++i) {
802 std::clog << "(" << pl1.land_[level][i].first << "," << pl1.land_[level][i].second << ") \n";
803 }
804 std::clog << "PL2 : \n";
805 for (std::size_t i = 0; i != pl2.land_[level].size(); ++i) {
806 std::clog << "(" << pl2.land_[level][i].first << "," << pl2.land_[level][i].second << ") \n";
807 }
808#endif
809
810 int p2Count = 0;
811 // In this case, I consider points at the infinity
812 for (std::size_t i = 1; i != pl1.land_[level].size() - 1; ++i) {
813 while (true) {
814 if ((pl1.land_[level][i].first >= pl2.land_[level][p2Count].first) &&
815 (pl1.land_[level][i].first <= pl2.land_[level][p2Count + 1].first))
816 break;
817 p2Count++;
818 }
819 double val = std::fabs(
820 function_value(pl2.land_[level][p2Count], pl2.land_[level][p2Count + 1], pl1.land_[level][i].first) -
821 pl1.land_[level][i].second);
822 if (maxDist <= val) maxDist = val;
823
824#ifdef DEBUG_TRACES
825 std::clog << pl1.land_[level][i].first << "in [" << pl2.land_[level][p2Count].first << ","
826 << pl2.land_[level][p2Count + 1].first << "] \n";
827 std::clog << "pl1[level][i].second : " << pl1.land_[level][i].second << std::endl;
828 std::clog << "function_value( pl2[level][p2Count] , pl2[level][p2Count+1] , pl1[level][i].first ) : "
829 << function_value(pl2.land_[level][p2Count], pl2.land_[level][p2Count + 1], pl1.land_[level][i].first)
830 << std::endl;
831 std::clog << "val : " << val << std::endl;
832#endif
833 }
834 }
835
836#ifdef DEBUG_TRACES
837 std::clog << "minimalNumberOfLevels : " << minimalNumberOfLevels << std::endl;
838#endif
839
840 if (minimalNumberOfLevels < pl1.land_.size()) {
841 for (std::size_t level = minimalNumberOfLevels; level != pl1.land_.size(); ++level) {
842 for (std::size_t i = 0; i != pl1.land_[level].size(); ++i) {
843#ifdef DEBUG_TRACES
844 std::clog << "pl1[level][i].second : " << pl1.land_[level][i].second << std::endl;
845#endif
846 if (maxDist < pl1.land_[level][i].second) maxDist = pl1.land_[level][i].second;
847 }
848 }
849 }
850 return maxDist;
851 }
852
853 std::vector<std::vector<std::pair<double, double> > > land_;
854 std::size_t number_of_functions_for_vectorization_;
855 std::size_t number_of_functions_for_projections_to_reals_;
856
857 void _construct_persistence_landscape_from_barcode(
858 const std::vector<std::pair<double, double> >& p,
859 std::size_t number_of_levels = std::numeric_limits<std::size_t>::max());
860 Persistence_landscape _multiply_landscape_by_real_number_not_overwrite(double x) const;
861 void _multiply_landscape_by_real_number_overwrite(double x);
862
863 // warning, this function can be only called after filling in the intervals vector.
864 void _set_up_numbers_of_functions_for_vectorization_and_projections_to_reals()
865 {
866 this->number_of_functions_for_vectorization_ = this->land_.size();
867 this->number_of_functions_for_projections_to_reals_ = this->land_.size();
868 }
869};
870
872{
873 if (this->land_.size() != rhs.land_.size()) {
874#ifdef DEBUG_TRACES
875 std::clog << "1\n";
876#endif
877 return false;
878 }
879 for (std::size_t level = 0; level != this->land_.size(); ++level) {
880 if (this->land_[level].size() != rhs.land_[level].size()) {
881#ifdef DEBUG_TRACES
882 std::clog << "this->land[level].size() : " << this->land_[level].size() << "\n";
883 std::clog << "rhs.land[level].size() : " << rhs.land_[level].size() << "\n";
884 std::clog << "2\n";
885#endif
886 return false;
887 }
888 for (std::size_t i = 0; i != this->land_[level].size(); ++i) {
889 if (!(almost_equal(this->land_[level][i].first, rhs.land_[level][i].first) &&
890 almost_equal(this->land_[level][i].second, rhs.land_[level][i].second))) {
891#ifdef DEBUG_TRACES
892 std::clog << "this->land[level][i] : " << this->land_[level][i].first << " " << this->land_[level][i].second
893 << "\n";
894 std::clog << "rhs.land[level][i] : " << rhs.land_[level][i].first << " " << rhs.land_[level][i].second << "\n";
895 std::clog << "3\n";
896#endif
897 return false;
898 }
899 }
900 }
901 return true;
902}
903
904inline void Persistence_landscape::_construct_persistence_landscape_from_barcode(
905 const std::vector<std::pair<double, double> >& p,
906 std::size_t number_of_levels)
907{
908#ifdef DEBUG_TRACES
909 std::clog << "Persistence_landscape::Persistence_landscape( const std::vector< std::pair< double , double > >& p )"
910 << std::endl;
911#endif
912
913 // this is a general algorithm to construct persistence landscapes.
914 std::vector<std::pair<double, double> > bars;
915 bars.insert(bars.begin(), p.begin(), p.end());
916 std::sort(bars.begin(), bars.end(), compare_points_sorting);
917
918#ifdef DEBUG_TRACES
919 std::clog << "Bars : \n";
920 for (std::size_t i = 0; i != bars.size(); ++i) {
921 std::clog << bars[i].first << " " << bars[i].second << "\n";
922 }
923#endif
924
925 std::vector<std::pair<double, double> > characteristicPoints(p.size());
926 for (std::size_t i = 0; i != bars.size(); ++i) {
927 characteristicPoints[i] =
928 std::make_pair((bars[i].first + bars[i].second) / 2.0, (bars[i].second - bars[i].first) / 2.0);
929 }
930 std::vector<std::vector<std::pair<double, double> > > Persistence_landscape;
931 std::size_t number_of_levels_in_the_landscape = 0;
932 while (!characteristicPoints.empty()) {
933#ifdef DEBUG_TRACES
934 for (std::size_t i = 0; i != characteristicPoints.size(); ++i) {
935 std::clog << "(" << characteristicPoints[i].first << " " << characteristicPoints[i].second << ")\n";
936 }
937#endif
938
939 std::vector<std::pair<double, double> > lambda_n;
940 lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
941 lambda_n.push_back(std::make_pair(minus_length(characteristicPoints[0]), 0));
942 lambda_n.push_back(characteristicPoints[0]);
943
944#ifdef DEBUG_TRACES
945 std::clog << "1 Adding to lambda_n : (" << -std::numeric_limits<int>::max() << " " << 0 << ") , ("
946 << minus_length(characteristicPoints[0]) << " " << 0 << ") , (" << characteristicPoints[0].first << " "
947 << characteristicPoints[0].second << ") \n";
948#endif
949
950 std::size_t i = 1;
951 std::vector<std::pair<double, double> > newCharacteristicPoints;
952 while (i < characteristicPoints.size()) {
953 std::size_t p = 1;
954 if ((minus_length(characteristicPoints[i]) >= minus_length(lambda_n[lambda_n.size() - 1])) &&
955 (birth_plus_deaths(characteristicPoints[i]) > birth_plus_deaths(lambda_n[lambda_n.size() - 1]))) {
956 if (minus_length(characteristicPoints[i]) < birth_plus_deaths(lambda_n[lambda_n.size() - 1])) {
957 std::pair<double, double> point = std::make_pair(
958 (minus_length(characteristicPoints[i]) + birth_plus_deaths(lambda_n[lambda_n.size() - 1])) / 2,
959 (birth_plus_deaths(lambda_n[lambda_n.size() - 1]) - minus_length(characteristicPoints[i])) / 2);
960 lambda_n.push_back(point);
961#ifdef DEBUG_TRACES
962 std::clog << "2 Adding to lambda_n : (" << point.first << " " << point.second << ")\n";
963#endif
964
965#ifdef DEBUG_TRACES
966 std::clog << "characteristicPoints[i+p] : " << characteristicPoints[i + p].first << " "
967 << characteristicPoints[i + p].second << "\n";
968 std::clog << "point : " << point.first << " " << point.second << "\n";
969#endif
970
971 while ((i + p < characteristicPoints.size()) &&
972 (almost_equal(minus_length(point), minus_length(characteristicPoints[i + p]))) &&
973 (birth_plus_deaths(point) <= birth_plus_deaths(characteristicPoints[i + p]))) {
974 newCharacteristicPoints.push_back(characteristicPoints[i + p]);
975#ifdef DEBUG_TRACES
976 std::clog << "3.5 Adding to newCharacteristicPoints : (" << characteristicPoints[i + p].first << " "
977 << characteristicPoints[i + p].second << ")\n";
978#endif
979 ++p;
980 }
981
982 newCharacteristicPoints.push_back(point);
983#ifdef DEBUG_TRACES
984 std::clog << "4 Adding to newCharacteristicPoints : (" << point.first << " " << point.second << ")\n";
985#endif
986
987 while ((i + p < characteristicPoints.size()) &&
988 (minus_length(point) <= minus_length(characteristicPoints[i + p])) &&
989 (birth_plus_deaths(point) >= birth_plus_deaths(characteristicPoints[i + p]))) {
990 newCharacteristicPoints.push_back(characteristicPoints[i + p]);
991#ifdef DEBUG_TRACES
992 std::clog << "characteristicPoints[i+p] : " << characteristicPoints[i + p].first << " "
993 << characteristicPoints[i + p].second << "\n";
994 std::clog << "point : " << point.first << " " << point.second << "\n";
995 std::clog << "characteristicPoints[i+p] birth and death : " << minus_length(characteristicPoints[i + p])
996 << " , " << birth_plus_deaths(characteristicPoints[i + p]) << "\n";
997 std::clog << "point birth and death : " << minus_length(point) << " , " << birth_plus_deaths(point) << "\n";
998
999 std::clog << "3 Adding to newCharacteristicPoints : (" << characteristicPoints[i + p].first << " "
1000 << characteristicPoints[i + p].second << ")\n";
1001#endif
1002 ++p;
1003 }
1004
1005 } else {
1006 lambda_n.push_back(std::make_pair(birth_plus_deaths(lambda_n[lambda_n.size() - 1]), 0));
1007 lambda_n.push_back(std::make_pair(minus_length(characteristicPoints[i]), 0));
1008#ifdef DEBUG_TRACES
1009 std::clog << "5 Adding to lambda_n : (" << birth_plus_deaths(lambda_n[lambda_n.size() - 1]) << " " << 0
1010 << ")\n";
1011 std::clog << "5 Adding to lambda_n : (" << minus_length(characteristicPoints[i]) << " " << 0 << ")\n";
1012#endif
1013 }
1014 lambda_n.push_back(characteristicPoints[i]);
1015#ifdef DEBUG_TRACES
1016 std::clog << "6 Adding to lambda_n : (" << characteristicPoints[i].first << " "
1017 << characteristicPoints[i].second << ")\n";
1018#endif
1019 } else {
1020 newCharacteristicPoints.push_back(characteristicPoints[i]);
1021#ifdef DEBUG_TRACES
1022 std::clog << "7 Adding to newCharacteristicPoints : (" << characteristicPoints[i].first << " "
1023 << characteristicPoints[i].second << ")\n";
1024#endif
1025 }
1026 i = i + p;
1027 }
1028 lambda_n.push_back(std::make_pair(birth_plus_deaths(lambda_n[lambda_n.size() - 1]), 0));
1029 lambda_n.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
1030
1031 characteristicPoints = newCharacteristicPoints;
1032
1033 lambda_n.erase(std::unique(lambda_n.begin(), lambda_n.end()), lambda_n.end());
1034 this->land_.push_back(lambda_n);
1035
1036 ++number_of_levels_in_the_landscape;
1037 if (number_of_levels == number_of_levels_in_the_landscape) {
1038 break;
1039 }
1040 }
1041}
1042
1043// this function find maximum of lambda_n
1044inline double Persistence_landscape::find_max(unsigned int lambda) const
1045{
1046 if (this->land_.size() < lambda) return 0;
1047 double maximum = -std::numeric_limits<int>::max();
1048 for (std::size_t i = 0; i != this->land_[lambda].size(); ++i) {
1049 if (this->land_[lambda][i].second > maximum) maximum = this->land_[lambda][i].second;
1050 }
1051 return maximum;
1052}
1053
1055{
1056 double result = 0;
1057 for (std::size_t i = 0; i != this->land_.size(); ++i) {
1058 for (std::size_t nr = 2; nr != this->land_[i].size() - 1; ++nr) {
1059 // it suffices to compute every planar integral and then sum them up for each lambda_n
1060 result += 0.5 * (this->land_[i][nr].first - this->land_[i][nr - 1].first) *
1061 (this->land_[i][nr].second + this->land_[i][nr - 1].second);
1062 }
1063 }
1064 return result;
1065}
1066
1068{
1069 double result = 0;
1070 if (level >= this->land_.size()) {
1071 // this landscape function is constantly equal 0, so is the integral.
1072 return result;
1073 }
1074 // also negative landscapes are assumed to be zero.
1075 if (level < 0) return 0;
1076
1077 for (std::size_t nr = 2; nr != this->land_[level].size() - 1; ++nr) {
1078 // it suffices to compute every planar integral and then sum them up for each lambda_n
1079 result += 0.5 * (this->land_[level][nr].first - this->land_[level][nr - 1].first) *
1080 (this->land_[level][nr].second + this->land_[level][nr - 1].second);
1081 }
1082
1083 return result;
1084}
1085
1087{
1088 double result = 0;
1089 for (std::size_t i = 0; i != this->land_.size(); ++i) {
1090 for (std::size_t nr = 2; nr != this->land_[i].size() - 1; ++nr) {
1091#ifdef DEBUG_TRACES
1092 std::clog << "nr : " << nr << "\n";
1093#endif
1094 // In this interval, the landscape has a form f(x) = ax+b. We want to compute integral of (ax+b)^p = 1/a *
1095 // (ax+b)^{p+1}/(p+1)
1096 auto [a, b] = compute_parameters_of_a_line(this->land_[i][nr], this->land_[i][nr - 1]);
1097
1098#ifdef DEBUG_TRACES
1099 std::clog << "(" << this->land_[i][nr].first << "," << this->land_[i][nr].second << ") , "
1100 << this->land_[i][nr - 1].first << "," << this->land_[i][nr].second << ")" << std::endl;
1101#endif
1102 if (this->land_[i][nr].first == this->land_[i][nr - 1].first) continue;
1103 if (a != 0) {
1104 result += 1 / (a * (p + 1)) *
1105 (std::pow((a * this->land_[i][nr].first + b), p + 1) -
1106 std::pow((a * this->land_[i][nr - 1].first + b), p + 1));
1107 } else {
1108 result += (this->land_[i][nr].first - this->land_[i][nr - 1].first) * (std::pow(this->land_[i][nr].second, p));
1109 }
1110#ifdef DEBUG_TRACES
1111 std::clog << "a : " << a << " , b : " << b << std::endl;
1112 std::clog << "result : " << result << std::endl;
1113#endif
1114 }
1115 }
1116 return result;
1117}
1118
1119// this is O(log(n)) algorithm, where n is number of points in this->land.
1120inline double Persistence_landscape::compute_value_at_a_given_point(unsigned int level, double x) const
1121{
1122 // in such a case lambda_level = 0.
1123 if (level >= this->land_.size()) return 0;
1124
1125 // we know that the points in this->land[level] are ordered according to x coordinate. Therefore, we can find the
1126 // point by using bisection:
1127 unsigned int coordBegin = 1;
1128 unsigned int coordEnd = this->land_[level].size() - 2;
1129
1130#ifdef DEBUG_TRACES
1131 std::clog << "Here \n";
1132 std::clog << "x : " << x << "\n";
1133 std::clog << "this->land[level][coordBegin].first : " << this->land_[level][coordBegin].first << "\n";
1134 std::clog << "this->land[level][coordEnd].first : " << this->land_[level][coordEnd].first << "\n";
1135#endif
1136
1137 // in this case x is outside the support of the landscape, therefore the value of the landscape is 0.
1138 if (x <= this->land_[level][coordBegin].first) return 0;
1139 if (x >= this->land_[level][coordEnd].first) return 0;
1140
1141#ifdef DEBUG_TRACES
1142 std::clog << "Entering to the while loop \n";
1143#endif
1144
1145 while (coordBegin + 1 != coordEnd) {
1146#ifdef DEBUG_TRACES
1147 std::clog << "coordBegin : " << coordBegin << "\n";
1148 std::clog << "coordEnd : " << coordEnd << "\n";
1149 std::clog << "this->land[level][coordBegin].first : " << this->land_[level][coordBegin].first << "\n";
1150 std::clog << "this->land[level][coordEnd].first : " << this->land_[level][coordEnd].first << "\n";
1151#endif
1152
1153 unsigned int newCord = (unsigned int)floor((coordEnd + coordBegin) / 2.0);
1154
1155#ifdef DEBUG_TRACES
1156 std::clog << "newCord : " << newCord << "\n";
1157 std::clog << "this->land[level][newCord].first : " << this->land_[level][newCord].first << "\n";
1158#endif
1159
1160 if (this->land_[level][newCord].first <= x) {
1161 coordBegin = newCord;
1162 if (this->land_[level][newCord].first == x) return this->land_[level][newCord].second;
1163 } else {
1164 coordEnd = newCord;
1165 }
1166 }
1167
1168#ifdef DEBUG_TRACES
1169 std::clog << "x : " << x << " is between : " << this->land_[level][coordBegin].first << " a "
1170 << this->land_[level][coordEnd].first << "\n";
1171 std::clog << "the y coords are : " << this->land_[level][coordBegin].second << " a "
1172 << this->land_[level][coordEnd].second << "\n";
1173 std::clog << "coordBegin : " << coordBegin << "\n";
1174 std::clog << "coordEnd : " << coordEnd << "\n";
1175#endif
1176 return function_value(this->land_[level][coordBegin], this->land_[level][coordEnd], x);
1177}
1178
1179inline void Persistence_landscape::_multiply_landscape_by_real_number_overwrite(double x)
1180{
1181 for (std::size_t dim = 0; dim != this->land_.size(); ++dim) {
1182 for (std::size_t i = 0; i != this->land_[dim].size(); ++i) {
1183 this->land_[dim][i].second *= x;
1184 }
1185 }
1186}
1187
1189{
1190 Persistence_landscape result;
1191 for (std::size_t level = 0; level != this->land_.size(); ++level) {
1192#ifdef DEBUG_TRACES
1193 std::clog << "level: " << level << std::endl;
1194#endif
1195 std::vector<std::pair<double, double> > lambda_n;
1196 lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
1197 for (std::size_t i = 1; i != this->land_[level].size(); ++i) {
1198#ifdef DEBUG_TRACES
1199 std::clog << "this->land[" << level << "][" << i << "] : " << this->land_[level][i].first << " "
1200 << this->land_[level][i].second << std::endl;
1201#endif
1202 // if a line segment between this->land[level][i-1] and this->land[level][i] crosses the x-axis, then we have to
1203 // add one landscape point t o result
1204 if ((this->land_[level][i - 1].second) * (this->land_[level][i].second) < 0) {
1205 double zero =
1206 find_zero_of_a_line_segment_between_those_two_points(this->land_[level][i - 1], this->land_[level][i]);
1207
1208 lambda_n.push_back(std::make_pair(zero, 0));
1209 lambda_n.push_back(std::make_pair(this->land_[level][i].first, std::fabs(this->land_[level][i].second)));
1210#ifdef DEBUG_TRACES
1211 std::clog << "Adding pair : (" << zero << ",0)" << std::endl;
1212 std::clog << "In the same step adding pair : (" << this->land_[level][i].first << ","
1213 << std::fabs(this->land_[level][i].second) << ") " << std::endl;
1214#endif
1215 } else {
1216 lambda_n.push_back(std::make_pair(this->land_[level][i].first, std::fabs(this->land_[level][i].second)));
1217#ifdef DEBUG_TRACES
1218 std::clog << "Adding pair : (" << this->land_[level][i].first << "," << std::fabs(this->land_[level][i].second)
1219 << ") " << std::endl;
1220#endif
1221 }
1222 }
1223 result.land_.push_back(lambda_n);
1224 }
1225 return result;
1226}
1227
1228inline Persistence_landscape* Persistence_landscape::new_abs()
1229{
1230 Persistence_landscape* result = new Persistence_landscape(*this);
1231 for (std::size_t level = 0; level != this->land_.size(); ++level) {
1232#ifdef DEBUG_TRACES
1233 std::clog << "level: " << level << std::endl;
1234#endif
1235 std::vector<std::pair<double, double> > lambda_n;
1236 lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
1237 for (std::size_t i = 1; i != this->land_[level].size(); ++i) {
1238#ifdef DEBUG_TRACES
1239 std::clog << "this->land[" << level << "][" << i << "] : " << this->land_[level][i].first << " "
1240 << this->land_[level][i].second << std::endl;
1241#endif
1242 // if a line segment between this->land[level][i-1] and this->land[level][i] crosses the x-axis, then we have to
1243 // add one landscape point t o result
1244 if ((this->land_[level][i - 1].second) * (this->land_[level][i].second) < 0) {
1245 double zero =
1246 find_zero_of_a_line_segment_between_those_two_points(this->land_[level][i - 1], this->land_[level][i]);
1247
1248 lambda_n.push_back(std::make_pair(zero, 0));
1249 lambda_n.push_back(std::make_pair(this->land_[level][i].first, std::fabs(this->land_[level][i].second)));
1250#ifdef DEBUG_TRACES
1251 std::clog << "Adding pair : (" << zero << ",0)" << std::endl;
1252 std::clog << "In the same step adding pair : (" << this->land_[level][i].first << ","
1253 << std::fabs(this->land_[level][i].second) << ") " << std::endl;
1254#endif
1255 } else {
1256 lambda_n.push_back(std::make_pair(this->land_[level][i].first, std::fabs(this->land_[level][i].second)));
1257#ifdef DEBUG_TRACES
1258 std::clog << "Adding pair : (" << this->land_[level][i].first << "," << std::fabs(this->land_[level][i].second)
1259 << ") " << std::endl;
1260#endif
1261 }
1262 }
1263 result->land_.push_back(lambda_n);
1264 }
1265 return result;
1266}
1267
1268inline Persistence_landscape Persistence_landscape::_multiply_landscape_by_real_number_not_overwrite(double x) const
1269{
1270 std::vector<std::vector<std::pair<double, double> > > result(this->land_.size());
1271 for (std::size_t dim = 0; dim != this->land_.size(); ++dim) {
1272 std::vector<std::pair<double, double> > lambda_dim(this->land_[dim].size());
1273 for (std::size_t i = 0; i != this->land_[dim].size(); ++i) {
1274 lambda_dim[i] = std::make_pair(this->land_[dim][i].first, x * this->land_[dim][i].second);
1275 }
1276 result[dim] = lambda_dim;
1277 }
1279 // CHANGE
1280 // res.land = result;
1281 res.land_.swap(result);
1282 return res;
1283}
1284
1285inline void Persistence_landscape::print_to_file(const char* filename) const
1286{
1287 std::ofstream write;
1288 write.open(filename);
1289 for (std::size_t dim = 0; dim != this->land_.size(); ++dim) {
1290 write << "#lambda_" << dim << std::endl;
1291 for (std::size_t i = 1; i != this->land_[dim].size() - 1; ++i) {
1292 write << this->land_[dim][i].first << " " << this->land_[dim][i].second << std::endl;
1293 }
1294 }
1295 write.close();
1296}
1297
1299{
1300 // removing the current content of the persistence landscape.
1301 this->land_.clear();
1302
1303 // this constructor reads persistence landscape form a file. This file have to be created by this software before head
1304 std::ifstream in;
1305 in.open(filename);
1306 if (!in.good()) {
1307#ifdef DEBUG_TRACES
1308 std::cerr << "The file : " << filename << " do not exist. The program will now terminate \n";
1309#endif
1310 throw std::invalid_argument("The persistence landscape file do not exist.");
1311 }
1312
1313 std::string line;
1314 std::vector<std::pair<double, double> > landscapeAtThisLevel;
1315
1316 bool isThisAFirsLine = true;
1317 while (in.good()) {
1318 getline(in, line);
1319 if (!(line.length() == 0 || line[0] == '#')) {
1320 std::stringstream lineSS;
1321 lineSS << line;
1322 double begin, end;
1323 lineSS >> begin;
1324 lineSS >> end;
1325 landscapeAtThisLevel.push_back(std::make_pair(begin, end));
1326#ifdef DEBUG_TRACES
1327 std::clog << "Reading a point : " << begin << " , " << end << std::endl;
1328#endif
1329 } else {
1330#ifdef DEBUG_TRACES
1331 std::clog << "IGNORE LINE\n";
1332#endif
1333 if (!isThisAFirsLine) {
1334 landscapeAtThisLevel.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
1335 this->land_.push_back(landscapeAtThisLevel);
1336 std::vector<std::pair<double, double> > newLevelOdLandscape;
1337 landscapeAtThisLevel.swap(newLevelOdLandscape);
1338 }
1339 landscapeAtThisLevel.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
1340 isThisAFirsLine = false;
1341 }
1342 }
1343 if (landscapeAtThisLevel.size() > 1) {
1344 // seems that the last line of the file is not finished with the newline sign. We need to put what we have in
1345 // landscapeAtThisLevel to the constructed landscape.
1346 landscapeAtThisLevel.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
1347 this->land_.push_back(landscapeAtThisLevel);
1348 }
1349
1350 in.close();
1351}
1352
1353inline void Persistence_landscape::plot(const char* filename,
1354 double xRangeBegin,
1355 double xRangeEnd,
1356 double yRangeBegin,
1357 double yRangeEnd,
1358 int from,
1359 int to)
1360{
1361 // this program create a gnuplot script file that allows to plot persistence diagram.
1362 std::ofstream out;
1363
1364 std::ostringstream gnuplot_script;
1365 gnuplot_script << filename << "_GnuplotScript";
1366 out.open(gnuplot_script.str().c_str());
1367
1368 if ((xRangeBegin != std::numeric_limits<double>::max()) || (xRangeEnd != std::numeric_limits<double>::max()) ||
1369 (yRangeBegin != std::numeric_limits<double>::max()) || (yRangeEnd != std::numeric_limits<double>::max())) {
1370 out << "set xrange [" << xRangeBegin << " : " << xRangeEnd << "]" << std::endl;
1371 out << "set yrange [" << yRangeBegin << " : " << yRangeEnd << "]" << std::endl;
1372 }
1373
1374 if (from == std::numeric_limits<int>::max()) {
1375 from = 0;
1376 }
1377 if (to == std::numeric_limits<int>::max()) {
1378 to = this->land_.size();
1379 }
1380
1381 out << "plot ";
1382 for (std::size_t lambda = std::min((std::size_t)from, this->land_.size());
1383 lambda != std::min((std::size_t)to, this->land_.size());
1384 ++lambda) {
1385 // out << " '-' using 1:2 title 'l" << lambda << "' with lp";
1386 out << " '-' using 1:2 notitle with lp";
1387 if (lambda + 1 != std::min((std::size_t)to, this->land_.size())) {
1388 out << ", \\";
1389 }
1390 out << std::endl;
1391 }
1392
1393 for (std::size_t lambda = std::min((std::size_t)from, this->land_.size());
1394 lambda != std::min((std::size_t)to, this->land_.size());
1395 ++lambda) {
1396 for (std::size_t i = 1; i != this->land_[lambda].size() - 1; ++i) {
1397 out << this->land_[lambda][i].first << " " << this->land_[lambda][i].second << std::endl;
1398 }
1399 out << "EOF" << std::endl;
1400 }
1401#ifdef DEBUG_TRACES
1402 std::clog << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
1403 << gnuplot_script.str().c_str() << "\'\"" << std::endl;
1404#endif
1405}
1406
1407} // namespace Persistence_representations
1408} // namespace Gudhi
1409
1410#endif // PERSISTENCE_LANDSCAPE_H_
A class implementing persistence landscapes data structures.
Definition Persistence_landscape.h:66
friend double compute_inner_product(const Persistence_landscape &l1, const Persistence_landscape &l2)
Definition Persistence_landscape.h:530
std::size_t number_of_projections_to_R() const
Definition Persistence_landscape.h:652
friend std::ostream & operator<<(std::ostream &out, const Persistence_landscape &land)
Definition Persistence_landscape.h:141
bool operator==(const Persistence_landscape &rhs) const
Definition Persistence_landscape.h:871
friend double compute_distance_of_landscapes(const Persistence_landscape &first, const Persistence_landscape &second, double p)
Definition Persistence_landscape.h:464
friend Persistence_landscape operator+(const Persistence_landscape &first, const Persistence_landscape &second)
Definition Persistence_landscape.h:326
double compute_scalar_product(const Persistence_landscape &second) const
Definition Persistence_landscape.h:754
friend Persistence_landscape operator-(const Persistence_landscape &first, const Persistence_landscape &second)
Definition Persistence_landscape.h:334
friend double compute_max_norm_distance_of_landscapes(const Persistence_landscape &first, const Persistence_landscape &second)
Definition Persistence_landscape.h:454
Persistence_landscape(const char *filename, unsigned int dimension=std::numeric_limits< unsigned int >::max(), std::size_t number_of_levels=std::numeric_limits< std::size_t >::max())
Definition Persistence_landscape.h:88
Persistence_landscape abs()
Definition Persistence_landscape.h:1188
double compute_integral_of_a_level_of_a_landscape(std::size_t level) const
Definition Persistence_landscape.h:1067
friend Persistence_landscape add_two_landscapes(const Persistence_landscape &land1, const Persistence_landscape &land2)
Definition Persistence_landscape.h:308
std::pair< double, double > get_y_range(std::size_t level=0) const
Definition Persistence_landscape.h:765
friend Persistence_landscape subtract_two_landscapes(const Persistence_landscape &land1, const Persistence_landscape &land2)
Definition Persistence_landscape.h:317
double compute_integral_of_landscape() const
Definition Persistence_landscape.h:1054
double find_max(unsigned int lambda) const
Definition Persistence_landscape.h:1044
Persistence_landscape()
Definition Persistence_landscape.h:71
Persistence_landscape operator-=(const Persistence_landscape &rhs)
Definition Persistence_landscape.h:367
double distance(const Persistence_landscape &second, double power=1) const
Definition Persistence_landscape.h:740
double operator()(unsigned int level, double x) const
Definition Persistence_landscape.h:449
double compute_value_at_a_given_point(unsigned int level, double x) const
Definition Persistence_landscape.h:1120
Persistence_landscape operator+=(const Persistence_landscape &rhs)
Definition Persistence_landscape.h:358
std::size_t size() const
Definition Persistence_landscape.h:520
double project_to_R(int number_of_function) const
Definition Persistence_landscape.h:643
Persistence_landscape operator/=(double x)
Definition Persistence_landscape.h:386
friend Persistence_landscape operator*(const Persistence_landscape &first, double con)
Definition Persistence_landscape.h:342
std::vector< double > vectorize(int number_of_function) const
Definition Persistence_landscape.h:658
double compute_maximum() const
Definition Persistence_landscape.h:406
void compute_average(const std::vector< Persistence_landscape * > &to_average)
Definition Persistence_landscape.h:682
Persistence_landscape operator*=(double x)
Definition Persistence_landscape.h:377
void print_to_file(const char *filename) const
Definition Persistence_landscape.h:1285
Persistence_landscape(const std::vector< std::pair< double, double > > &p, std::size_t number_of_levels=std::numeric_limits< std::size_t >::max())
Definition Persistence_landscape.h:76
friend Persistence_landscape operator*(double con, const Persistence_landscape &first)
Definition Persistence_landscape.h:350
std::size_t number_of_vectorize_functions() const
Definition Persistence_landscape.h:676
bool operator!=(const Persistence_landscape &rhs) const
Definition Persistence_landscape.h:401
void load_landscape_from_file(const char *filename)
Definition Persistence_landscape.h:1298
This file contain an implementation of some common procedures used in the Persistence_representations...
double find_zero_of_a_line_segment_between_those_two_points(const std::pair< double, double > &p1, const std::pair< double, double > &p2)
Definition common_persistence_representations.h:134
std::pair< double, double > compute_parameters_of_a_line(const std::pair< double, double > &p1, const std::pair< double, double > &p2)
Definition common_persistence_representations.h:121
double function_value(const std::pair< double, double > &p1, const std::pair< double, double > &p2, double x)
Definition common_persistence_representations.h:158
bool almost_equal(double a, double b)
Definition common_persistence_representations.h:65
std::vector< std::pair< double, double > > read_persistence_intervals_in_one_dimension_from_file(std::string const &filename, int dimension=-1, double what_to_substitute_for_infinite_bar=-1)
Definition read_persistence_from_file.h:44
Gudhi namespace.
Definition SimplicialComplexForAlpha.h:14