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 
30 namespace Gudhi {
31 namespace Persistence_representations {
32 
33 // pre declaration
35 template <typename operation>
36 Persistence_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 
461 Persistence_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 
472 bool 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 
501 Persistence_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 
507 void 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
652 double 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.
723 double 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 
782 std::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 
801 void 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 
809 bool AbsDbg = false;
811  Persistence_landscape result;
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 
851 Persistence_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 
892 Persistence_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 
908 void 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 
974 template <typename T>
975 Persistence_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  }
982  Persistence_landscape result;
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 
1112 double 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 
1172 double 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 
1208 double 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 
1214 bool comparePairsForMerging(std::pair<double, unsigned> first, std::pair<double, unsigned> second) {
1215  return (first.first < second.first);
1216 }
1217 
1218 double 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 
1325 void 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
friend std::ostream & operator<<(std::ostream &out, Persistence_landscape &land)
Definition: Persistence_landscape.h:782
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
std::vector< double > vectorize(int number_of_function) const
Definition: Persistence_landscape.h:320
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
double compute_maximum() const
Definition: Persistence_landscape.h:217
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
std::pair< double, double > get_y_range(size_t level=0) const
Definition: Persistence_landscape.h:423
friend Persistence_landscape operator*(double con, const Persistence_landscape &first)
Definition: Persistence_landscape.h:166
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
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14