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