Simplex_tree.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): ClĂ©ment Maria
4  *
5  * Copyright (C) 2014 Inria
6  *
7  * Modification(s):
8  * - YYYY/MM Author: Description of the modification
9  */
10 
11 #ifndef SIMPLEX_TREE_H_
12 #define SIMPLEX_TREE_H_
13 
14 #include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h>
15 #include <gudhi/Simplex_tree/Simplex_tree_siblings.h>
16 #include <gudhi/Simplex_tree/Simplex_tree_iterators.h>
17 #include <gudhi/Simplex_tree/indexing_tag.h>
18 
19 #include <gudhi/reader_utils.h>
21 #include <gudhi/Debug_utils.h>
22 
23 #include <boost/container/flat_map.hpp>
24 #include <boost/iterator/transform_iterator.hpp>
25 #include <boost/graph/adjacency_list.hpp>
26 #include <boost/range/adaptor/reversed.hpp>
27 #include <boost/container/static_vector.hpp>
28 
29 #ifdef GUDHI_USE_TBB
30 #include <tbb/parallel_sort.h>
31 #endif
32 
33 #include <utility>
34 #include <vector>
35 #include <functional> // for greater<>
36 #include <stdexcept>
37 #include <limits> // Inf
38 #include <initializer_list>
39 #include <algorithm> // for std::max
40 #include <cstdint> // for std::uint32_t
41 #include <iterator> // for std::distance
42 
43 namespace Gudhi {
44 
57 enum class Extended_simplex_type {UP, DOWN, EXTRA};
58 
59 struct Simplex_tree_options_full_featured;
60 
74 template<typename SimplexTreeOptions = Simplex_tree_options_full_featured>
75 class Simplex_tree {
76  public:
78  typedef typename Options::Indexing_tag Indexing_tag;
91 
92  /* Type of node in the simplex tree. */
93  typedef Simplex_tree_node_explicit_storage<Simplex_tree> Node;
94  /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
95  // Note: this wastes space when Vertex_handle is 32 bits and Node is aligned on 64 bits. It would be better to use a
96  // flat_set (with our own comparator) where we can control the layout of the struct (put Vertex_handle and
97  // Simplex_key next to each other).
98  typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary;
99 
100  /* \brief Set of nodes sharing a same parent in the simplex tree. */
101  /* \brief Set of nodes sharing a same parent in the simplex tree. */
102  typedef Simplex_tree_siblings<Simplex_tree, Dictionary> Siblings;
103 
104 
105 
106  struct Key_simplex_base_real {
107  Key_simplex_base_real() : key_(-1) {}
108  void assign_key(Simplex_key k) { key_ = k; }
109  Simplex_key key() const { return key_; }
110  private:
111  Simplex_key key_;
112  };
113  struct Key_simplex_base_dummy {
114  Key_simplex_base_dummy() {}
115  // Undefined so it will not link
116  void assign_key(Simplex_key);
117  Simplex_key key() const;
118  };
119  struct Extended_filtration_data {
120  Filtration_value minval;
121  Filtration_value maxval;
122  Extended_filtration_data(){}
123  Extended_filtration_data(Filtration_value vmin, Filtration_value vmax): minval(vmin), maxval(vmax) {}
124  };
125  typedef typename std::conditional<Options::store_key, Key_simplex_base_real, Key_simplex_base_dummy>::type
126  Key_simplex_base;
127 
128  struct Filtration_simplex_base_real {
129  Filtration_simplex_base_real() : filt_(0) {}
130  void assign_filtration(Filtration_value f) { filt_ = f; }
131  Filtration_value filtration() const { return filt_; }
132  private:
133  Filtration_value filt_;
134  };
135  struct Filtration_simplex_base_dummy {
136  Filtration_simplex_base_dummy() {}
137  void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); }
138  Filtration_value filtration() const { return 0; }
139  };
140  typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real,
141  Filtration_simplex_base_dummy>::type Filtration_simplex_base;
142 
143  public:
149  typedef typename Dictionary::iterator Simplex_handle;
150 
151  private:
152  typedef typename Dictionary::iterator Dictionary_it;
153  typedef typename Dictionary_it::value_type Dit_value_t;
154 
155  struct return_first {
156  Vertex_handle operator()(const Dit_value_t& p_sh) const {
157  return p_sh.first;
158  }
159  };
160 
161  public:
173  typedef boost::transform_iterator<return_first, Dictionary_it> Complex_vertex_iterator;
175  typedef boost::iterator_range<Complex_vertex_iterator> Complex_vertex_range;
179  typedef Simplex_tree_simplex_vertex_iterator<Simplex_tree> Simplex_vertex_iterator;
181  typedef boost::iterator_range<Simplex_vertex_iterator> Simplex_vertex_range;
183  typedef std::vector<Simplex_handle> Cofaces_simplex_range;
187  typedef Simplex_tree_boundary_simplex_iterator<Simplex_tree> Boundary_simplex_iterator;
189  typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range;
193  typedef Simplex_tree_complex_simplex_iterator<Simplex_tree> Complex_simplex_iterator;
195  typedef boost::iterator_range<Complex_simplex_iterator> Complex_simplex_range;
200  typedef Simplex_tree_skeleton_simplex_iterator<Simplex_tree> Skeleton_simplex_iterator;
203  typedef boost::iterator_range<Skeleton_simplex_iterator> Skeleton_simplex_range;
205  typedef std::vector<Simplex_handle> Filtration_simplex_range;
209  typedef typename Filtration_simplex_range::const_iterator Filtration_simplex_iterator;
210 
211  /* @} */ // end name range and iterator types
217  Complex_vertex_range complex_vertex_range() {
218  return Complex_vertex_range(
219  boost::make_transform_iterator(root_.members_.begin(), return_first()),
220  boost::make_transform_iterator(root_.members_.end(), return_first()));
221  }
222 
228  Complex_simplex_range complex_simplex_range() {
229  return Complex_simplex_range(Complex_simplex_iterator(this),
230  Complex_simplex_iterator());
231  }
232 
242  Skeleton_simplex_range skeleton_simplex_range(int dim) {
243  return Skeleton_simplex_range(Skeleton_simplex_iterator(this, dim),
244  Skeleton_simplex_iterator());
245  }
246 
262  Filtration_simplex_range const& filtration_simplex_range(Indexing_tag = Indexing_tag()) {
263  maybe_initialize_filtration();
264  return filtration_vect_;
265  }
266 
273  Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) const {
274  GUDHI_CHECK(sh != null_simplex(), "empty simplex");
275  return Simplex_vertex_range(Simplex_vertex_iterator(this, sh),
276  Simplex_vertex_iterator(this));
277  }
278 
293  template<class SimplexHandle>
294  Boundary_simplex_range boundary_simplex_range(SimplexHandle sh) {
295  return Boundary_simplex_range(Boundary_simplex_iterator(this, sh),
296  Boundary_simplex_iterator(this));
297  }
298  // end range and iterator methods
305  : null_vertex_(-1),
306  root_(nullptr, null_vertex_),
307  filtration_vect_(),
308  dimension_(-1) { }
309 
311  Simplex_tree(const Simplex_tree& complex_source) {
312 #ifdef DEBUG_TRACES
313  std::clog << "Simplex_tree copy constructor" << std::endl;
314 #endif // DEBUG_TRACES
315  copy_from(complex_source);
316  }
317 
321  Simplex_tree(Simplex_tree && complex_source) {
322 #ifdef DEBUG_TRACES
323  std::clog << "Simplex_tree move constructor" << std::endl;
324 #endif // DEBUG_TRACES
325  move_from(complex_source);
326 
327  // just need to set dimension_ on source to make it available again
328  // (filtration_vect_ and members are already set from the move)
329  complex_source.dimension_ = -1;
330  }
331 
334  root_members_recursive_deletion();
335  }
336 
338  Simplex_tree& operator= (const Simplex_tree& complex_source) {
339 #ifdef DEBUG_TRACES
340  std::clog << "Simplex_tree copy assignment" << std::endl;
341 #endif // DEBUG_TRACES
342  // Self-assignment detection
343  if (&complex_source != this) {
344  // We start by deleting root_ if not empty
345  root_members_recursive_deletion();
346 
347  copy_from(complex_source);
348  }
349  return *this;
350  }
351 
355  Simplex_tree& operator=(Simplex_tree&& complex_source) {
356 #ifdef DEBUG_TRACES
357  std::clog << "Simplex_tree move assignment" << std::endl;
358 #endif // DEBUG_TRACES
359  // Self-assignment detection
360  if (&complex_source != this) {
361  // root_ deletion in case it was not empty
362  root_members_recursive_deletion();
363 
364  move_from(complex_source);
365  }
366  return *this;
367  } // end constructor/destructor
369 
370  private:
371  // Copy from complex_source to "this"
372  void copy_from(const Simplex_tree& complex_source) {
373  null_vertex_ = complex_source.null_vertex_;
374  filtration_vect_.clear();
375  dimension_ = complex_source.dimension_;
376  auto root_source = complex_source.root_;
377 
378  // root members copy
379  root_.members() = Dictionary(boost::container::ordered_unique_range, root_source.members().begin(), root_source.members().end());
380  // Needs to reassign children
381  for (auto& map_el : root_.members()) {
382  map_el.second.assign_children(&root_);
383  }
384  rec_copy(&root_, &root_source);
385  }
386 
388  void rec_copy(Siblings *sib, Siblings *sib_source) {
389  for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin();
390  sh != sib->members().end(); ++sh, ++sh_source) {
391  if (has_children(sh_source)) {
392  Siblings * newsib = new Siblings(sib, sh_source->first);
393  newsib->members_.reserve(sh_source->second.children()->members().size());
394  for (auto & child : sh_source->second.children()->members())
395  newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(newsib, child.second.filtration()));
396  rec_copy(newsib, sh_source->second.children());
397  sh->second.assign_children(newsib);
398  }
399  }
400  }
401 
402  // Move from complex_source to "this"
403  void move_from(Simplex_tree& complex_source) {
404  null_vertex_ = std::move(complex_source.null_vertex_);
405  root_ = std::move(complex_source.root_);
406  filtration_vect_ = std::move(complex_source.filtration_vect_);
407  dimension_ = std::move(complex_source.dimension_);
408 
409  // Need to update root members (children->oncles and children need to point on the new root pointer)
410  for (auto& map_el : root_.members()) {
411  if (map_el.second.children() != &(complex_source.root_)) {
412  // reset children->oncles with the moved root_ pointer value
413  map_el.second.children()->oncles_ = &root_;
414  } else {
415  // if simplex is of dimension 0, oncles_ shall be nullptr
416  GUDHI_CHECK(map_el.second.children()->oncles_ == nullptr,
417  std::invalid_argument("Simplex_tree move constructor from an invalid Simplex_tree"));
418  // and children points on root_ - to be moved
419  map_el.second.assign_children(&root_);
420  }
421  }
422  }
423 
424  // delete all root_.members() recursively
425  void root_members_recursive_deletion() {
426  for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh) {
427  if (has_children(sh)) {
428  rec_delete(sh->second.children());
429  }
430  }
431  root_.members().clear();
432  }
433 
434  // Recursive deletion
435  void rec_delete(Siblings * sib) {
436  for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
437  if (has_children(sh)) {
438  rec_delete(sh->second.children());
439  }
440  }
441  delete sib;
442  }
443 
444  public:
447  if ((null_vertex_ != st2.null_vertex_) ||
448  (dimension_ != st2.dimension_))
449  return false;
450  return rec_equal(&root_, &st2.root_);
451  }
452 
455  return (!(*this == st2));
456  }
457 
458  private:
460  bool rec_equal(Siblings* s1, Siblings* s2) {
461  if (s1->members().size() != s2->members().size())
462  return false;
463  for (auto sh1 = s1->members().begin(), sh2 = s2->members().begin();
464  (sh1 != s1->members().end() && sh2 != s2->members().end()); ++sh1, ++sh2) {
465  if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration())
466  return false;
467  if (has_children(sh1) != has_children(sh2))
468  return false;
469  // Recursivity on children only if both have children
470  else if (has_children(sh1))
471  if (!rec_equal(sh1->second.children(), sh2->second.children()))
472  return false;
473  }
474  return true;
475  }
476 
481  static Filtration_value filtration_(Simplex_handle sh) {
482  GUDHI_CHECK (sh != null_simplex(), "null simplex");
483  return sh->second.filtration();
484  }
485 
486  public:
492  static Simplex_key key(Simplex_handle sh) {
493  return sh->second.key();
494  }
495 
500  Simplex_handle simplex(Simplex_key idx) const {
501  return filtration_vect_[idx];
502  }
503 
509  static Filtration_value filtration(Simplex_handle sh) {
510  if (sh != null_simplex()) {
511  return sh->second.filtration();
512  } else {
513  return std::numeric_limits<Filtration_value>::infinity();
514  }
515  }
516 
520  void assign_filtration(Simplex_handle sh, Filtration_value fv) {
521  GUDHI_CHECK(sh != null_simplex(),
522  std::invalid_argument("Simplex_tree::assign_filtration - cannot assign filtration on null_simplex"));
523  sh->second.assign_filtration(fv);
524  }
525 
530  static Simplex_handle null_simplex() {
531  return Dictionary_it(nullptr);
532  }
533 
535  static Simplex_key null_key() {
536  return -1;
537  }
538 
541  Vertex_handle null_vertex() const {
542  return null_vertex_;
543  }
544 
546  size_t num_vertices() const {
547  return root_.members_.size();
548  }
549 
550  public:
552  size_t num_simplices() {
553  return num_simplices(&root_);
554  }
555 
556  private:
558  size_t num_simplices(Siblings * sib) {
559  auto sib_begin = sib->members().begin();
560  auto sib_end = sib->members().end();
561  size_t simplices_number = sib_end - sib_begin;
562  for (auto sh = sib_begin; sh != sib_end; ++sh) {
563  if (has_children(sh)) {
564  simplices_number += num_simplices(sh->second.children());
565  }
566  }
567  return simplices_number;
568  }
569 
570  public:
574  int dimension(Simplex_handle sh) {
575  Siblings * curr_sib = self_siblings(sh);
576  int dim = 0;
577  while (curr_sib != nullptr) {
578  ++dim;
579  curr_sib = curr_sib->oncles();
580  }
581  return dim - 1;
582  }
583 
585  int upper_bound_dimension() const {
586  return dimension_;
587  }
588 
593  int dimension() {
594  if (dimension_to_be_lowered_)
595  lower_upper_bound_dimension();
596  return dimension_;
597  }
598 
601  template<class SimplexHandle>
602  bool has_children(SimplexHandle sh) const {
603  // Here we rely on the root using null_vertex(), which cannot match any real vertex.
604  return (sh->second.children()->parent() == sh->first);
605  }
606 
614  template<class InputVertexRange = std::initializer_list<Vertex_handle>>
615  Simplex_handle find(const InputVertexRange & s) {
616  auto first = std::begin(s);
617  auto last = std::end(s);
618 
619  if (first == last)
620  return null_simplex(); // ----->>
621 
622  // Copy before sorting
623  std::vector<Vertex_handle> copy(first, last);
624  std::sort(std::begin(copy), std::end(copy));
625  return find_simplex(copy);
626  }
627 
628  private:
630  Simplex_handle find_simplex(const std::vector<Vertex_handle> & simplex) {
631  Siblings * tmp_sib = &root_;
632  Dictionary_it tmp_dit;
633  auto vi = simplex.begin();
634  if (Options::contiguous_vertices) {
635  // Equivalent to the first iteration of the normal loop
636  GUDHI_CHECK(contiguous_vertices(), "non-contiguous vertices");
637  Vertex_handle v = *vi++;
638  if(v < 0 || v >= static_cast<Vertex_handle>(root_.members_.size()))
639  return null_simplex();
640  tmp_dit = root_.members_.begin() + v;
641  if (vi == simplex.end())
642  return tmp_dit;
643  if (!has_children(tmp_dit))
644  return null_simplex();
645  tmp_sib = tmp_dit->second.children();
646  }
647  for (;;) {
648  tmp_dit = tmp_sib->members_.find(*vi++);
649  if (tmp_dit == tmp_sib->members_.end())
650  return null_simplex();
651  if (vi == simplex.end())
652  return tmp_dit;
653  if (!has_children(tmp_dit))
654  return null_simplex();
655  tmp_sib = tmp_dit->second.children();
656  }
657  }
658 
661  Simplex_handle find_vertex(Vertex_handle v) {
662  if (Options::contiguous_vertices) {
663  assert(contiguous_vertices());
664  return root_.members_.begin() + v;
665  } else {
666  return root_.members_.find(v);
667  }
668  }
669 
670  public:
672  bool contiguous_vertices() const {
673  if (root_.members_.empty()) return true;
674  if (root_.members_.begin()->first != 0) return false;
675  if (std::prev(root_.members_.end())->first != static_cast<Vertex_handle>(root_.members_.size() - 1)) return false;
676  return true;
677  }
678 
679  private:
694  std::pair<Simplex_handle, bool> insert_vertex_vector(const std::vector<Vertex_handle>& simplex,
695  Filtration_value filtration) {
696  Siblings * curr_sib = &root_;
697  std::pair<Simplex_handle, bool> res_insert;
698  auto vi = simplex.begin();
699  for (; vi != simplex.end() - 1; ++vi) {
700  GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
701  res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
702  if (!(has_children(res_insert.first))) {
703  res_insert.first->second.assign_children(new Siblings(curr_sib, *vi));
704  }
705  curr_sib = res_insert.first->second.children();
706  }
707  GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
708  res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
709  if (!res_insert.second) {
710  // if already in the complex
711  if (res_insert.first->second.filtration() > filtration) {
712  // if filtration value modified
713  res_insert.first->second.assign_filtration(filtration);
714  return res_insert;
715  }
716  // if filtration value unchanged
717  return std::pair<Simplex_handle, bool>(null_simplex(), false);
718  }
719  // otherwise the insertion has succeeded - size is a size_type
720  if (static_cast<int>(simplex.size()) - 1 > dimension_) {
721  // Update dimension if needed
722  dimension_ = static_cast<int>(simplex.size()) - 1;
723  }
724  return res_insert;
725  }
726 
727  public:
751  template<class InputVertexRange = std::initializer_list<Vertex_handle>>
752  std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex,
753  Filtration_value filtration = 0) {
754  auto first = std::begin(simplex);
755  auto last = std::end(simplex);
756 
757  if (first == last)
758  return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->>
759 
760  // Copy before sorting
761  std::vector<Vertex_handle> copy(first, last);
762  std::sort(std::begin(copy), std::end(copy));
763  return insert_vertex_vector(copy, filtration);
764  }
765 
780  template<class InputVertexRange = std::initializer_list<Vertex_handle>>
781  std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex,
782  Filtration_value filtration = 0) {
783  auto first = std::begin(Nsimplex);
784  auto last = std::end(Nsimplex);
785 
786  if (first == last)
787  return { null_simplex(), true }; // FIXME: false would make more sense to me.
788 
789  thread_local std::vector<Vertex_handle> copy;
790  copy.clear();
791  copy.insert(copy.end(), first, last);
792  std::sort(copy.begin(), copy.end());
793  auto last_unique = std::unique(copy.begin(), copy.end());
794  copy.erase(last_unique, copy.end());
795  GUDHI_CHECK_code(
796  for (Vertex_handle v : copy)
797  GUDHI_CHECK(v != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
798  )
799  // Update dimension if needed. We could wait to see if the insertion succeeds, but I doubt there is much to gain.
800  dimension_ = (std::max)(dimension_, static_cast<int>(std::distance(copy.begin(), copy.end())) - 1);
801 
802  return rec_insert_simplex_and_subfaces_sorted(root(), copy.begin(), copy.end(), filtration);
803  }
804 
805  private:
806  // To insert {1,2,3,4}, we insert {2,3,4} twice, once at the root, and once below 1.
807  template<class ForwardVertexIterator>
808  std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces_sorted(Siblings* sib,
809  ForwardVertexIterator first,
810  ForwardVertexIterator last,
811  Filtration_value filt) {
812  // An alternative strategy would be:
813  // - try to find the complete simplex, if found (and low filtration) exit
814  // - insert all the vertices at once in sib
815  // - loop over those (new or not) simplices, with a recursive call(++first, last)
816  Vertex_handle vertex_one = *first;
817  auto&& dict = sib->members();
818  auto insertion_result = dict.emplace(vertex_one, Node(sib, filt));
819  Simplex_handle simplex_one = insertion_result.first;
820  bool one_is_new = insertion_result.second;
821  if (!one_is_new) {
822  if (filtration(simplex_one) > filt) {
823  assign_filtration(simplex_one, filt);
824  } else {
825  // FIXME: this interface makes no sense, and it doesn't seem to be tested.
826  insertion_result.first = null_simplex();
827  }
828  }
829  if (++first == last) return insertion_result;
830  if (!has_children(simplex_one))
831  // TODO: have special code here, we know we are building the whole subtree from scratch.
832  simplex_one->second.assign_children(new Siblings(sib, vertex_one));
833  auto res = rec_insert_simplex_and_subfaces_sorted(simplex_one->second.children(), first, last, filt);
834  // No need to continue if the full simplex was already there with a low enough filtration value.
835  if (res.first != null_simplex()) rec_insert_simplex_and_subfaces_sorted(sib, first, last, filt);
836  return res;
837  }
838 
839  public:
842  void assign_key(Simplex_handle sh, Simplex_key key) {
843  sh->second.assign_key(key);
844  }
845 
849  std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) {
850  assert(dimension(sh) == 1);
851  return { find_vertex(sh->first), find_vertex(self_siblings(sh)->parent()) };
852  }
853 
855  template<class SimplexHandle>
856  static Siblings* self_siblings(SimplexHandle sh) {
857  if (sh->second.children()->parent() == sh->first)
858  return sh->second.children()->oncles();
859  else
860  return sh->second.children();
861  }
862 
863  public:
865  Siblings * root() {
866  return &root_;
867  }
868 
873  void set_dimension(int dimension) {
874  dimension_to_be_lowered_ = false;
875  dimension_ = dimension;
876  }
877 
878  public:
887  filtration_vect_.clear();
888  filtration_vect_.reserve(num_simplices());
889  for (Simplex_handle sh : complex_simplex_range())
890  filtration_vect_.push_back(sh);
891 
892  /* We use stable_sort here because with libstdc++ it is faster than sort.
893  * is_before_in_filtration is now a total order, but we used to call
894  * stable_sort for the following heuristic:
895  * The use of a depth-first traversal of the simplex tree, provided by
896  * complex_simplex_range(), combined with a stable sort is meant to
897  * optimize the order of simplices with same filtration value. The
898  * heuristic consists in inserting the cofaces of a simplex as soon as
899  * possible.
900  */
901 #ifdef GUDHI_USE_TBB
902  tbb::parallel_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
903 #else
904  std::stable_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
905 #endif
906  }
911  if (filtration_vect_.empty()) {
912  initialize_filtration();
913  }
914  }
920  filtration_vect_.clear();
921  }
922 
923  private:
936  void rec_coface(std::vector<Vertex_handle> &vertices, Siblings *curr_sib, int curr_nbVertices,
937  std::vector<Simplex_handle>& cofaces, bool star, int nbVertices) {
938  if (!(star || curr_nbVertices <= nbVertices)) // dimension of actual simplex <= nbVertices
939  return;
940  for (Simplex_handle simplex = curr_sib->members().begin(); simplex != curr_sib->members().end(); ++simplex) {
941  if (vertices.empty()) {
942  // If we reached the end of the vertices, and the simplex has more vertices than the given simplex
943  // => we found a coface
944 
945  // Add a coface if we wan't the star or if the number of vertices of the current simplex matches with nbVertices
946  bool addCoface = (star || curr_nbVertices == nbVertices);
947  if (addCoface)
948  cofaces.push_back(simplex);
949  if ((!addCoface || star) && has_children(simplex)) // Rec call
950  rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
951  } else {
952  if (simplex->first == vertices.back()) {
953  // If curr_sib matches with the top vertex
954  bool equalDim = (star || curr_nbVertices == nbVertices); // dimension of actual simplex == nbVertices
955  bool addCoface = vertices.size() == 1 && equalDim;
956  if (addCoface)
957  cofaces.push_back(simplex);
958  if ((!addCoface || star) && has_children(simplex)) {
959  // Rec call
960  Vertex_handle tmp = vertices.back();
961  vertices.pop_back();
962  rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
963  vertices.push_back(tmp);
964  }
965  } else if (simplex->first > vertices.back()) {
966  return;
967  } else {
968  // (simplex->first < vertices.back()
969  if (has_children(simplex))
970  rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
971  }
972  }
973  }
974  }
975 
976  public:
982  Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex) {
983  return cofaces_simplex_range(simplex, 0);
984  }
985 
993  Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension) {
994  Cofaces_simplex_range cofaces;
995  // codimension must be positive or null integer
996  assert(codimension >= 0);
997  Simplex_vertex_range rg = simplex_vertex_range(simplex);
998  std::vector<Vertex_handle> copy(rg.begin(), rg.end());
999  if (codimension + static_cast<int>(copy.size()) > dimension_ + 1 ||
1000  (codimension == 0 && static_cast<int>(copy.size()) > dimension_)) // n+codimension greater than dimension_
1001  return cofaces;
1002  // must be sorted in decreasing order
1003  assert(std::is_sorted(copy.begin(), copy.end(), std::greater<Vertex_handle>()));
1004  bool star = codimension == 0;
1005  rec_coface(copy, &root_, 1, cofaces, star, codimension + static_cast<int>(copy.size()));
1006  return cofaces;
1007  }
1008 
1009  private:
1017  bool reverse_lexicographic_order(Simplex_handle sh1, Simplex_handle sh2) {
1018  Simplex_vertex_range rg1 = simplex_vertex_range(sh1);
1019  Simplex_vertex_range rg2 = simplex_vertex_range(sh2);
1020  Simplex_vertex_iterator it1 = rg1.begin();
1021  Simplex_vertex_iterator it2 = rg2.begin();
1022  while (it1 != rg1.end() && it2 != rg2.end()) {
1023  if (*it1 == *it2) {
1024  ++it1;
1025  ++it2;
1026  } else {
1027  return *it1 < *it2;
1028  }
1029  }
1030  return ((it1 == rg1.end()) && (it2 != rg2.end()));
1031  }
1032 
1039  struct is_before_in_filtration {
1040  explicit is_before_in_filtration(Simplex_tree * st)
1041  : st_(st) { }
1042 
1043  bool operator()(const Simplex_handle sh1, const Simplex_handle sh2) const {
1044  // Not using st_->filtration(sh1) because it uselessly tests for null_simplex.
1045  if (sh1->second.filtration() != sh2->second.filtration()) {
1046  return sh1->second.filtration() < sh2->second.filtration();
1047  }
1048  // is sh1 a proper subface of sh2
1049  return st_->reverse_lexicographic_order(sh1, sh2);
1050  }
1051 
1052  Simplex_tree * st_;
1053  };
1054 
1055  public:
1079  template<class OneSkeletonGraph>
1080  void insert_graph(const OneSkeletonGraph& skel_graph) {
1081  // the simplex tree must be empty
1082  assert(num_simplices() == 0);
1083 
1084  if (boost::num_vertices(skel_graph) == 0) {
1085  return;
1086  }
1087  if (num_edges(skel_graph) == 0) {
1088  dimension_ = 0;
1089  } else {
1090  dimension_ = 1;
1091  }
1092 
1093  root_.members_.reserve(boost::num_vertices(skel_graph));
1094 
1095  typename boost::graph_traits<OneSkeletonGraph>::vertex_iterator v_it,
1096  v_it_end;
1097  for (std::tie(v_it, v_it_end) = boost::vertices(skel_graph); v_it != v_it_end;
1098  ++v_it) {
1099  root_.members_.emplace_hint(
1100  root_.members_.end(), *v_it,
1101  Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it)));
1102  }
1103  std::pair<typename boost::graph_traits<OneSkeletonGraph>::edge_iterator,
1104  typename boost::graph_traits<OneSkeletonGraph>::edge_iterator> boost_edges = boost::edges(skel_graph);
1105  // boost_edges.first is the equivalent to boost_edges.begin()
1106  // boost_edges.second is the equivalent to boost_edges.end()
1107  for (; boost_edges.first != boost_edges.second; boost_edges.first++) {
1108  auto edge = *(boost_edges.first);
1109  auto u = source(edge, skel_graph);
1110  auto v = target(edge, skel_graph);
1111  if (u == v) throw "Self-loops are not simplicial";
1112  // We cannot skip edges with the wrong orientation and expect them to
1113  // come a second time with the right orientation, that does not always
1114  // happen in practice. emplace() should be a NOP when an element with the
1115  // same key is already there, so seeing the same edge multiple times is
1116  // ok.
1117  // Should we actually forbid multiple edges? That would be consistent
1118  // with rejecting self-loops.
1119  if (v < u) std::swap(u, v);
1120  auto sh = find_vertex(u);
1121  if (!has_children(sh)) {
1122  sh->second.assign_children(new Siblings(&root_, sh->first));
1123  }
1124 
1125  sh->second.children()->members().emplace(v,
1126  Node(sh->second.children(), boost::get(edge_filtration_t(), skel_graph, edge)));
1127  }
1128  }
1129 
1141  void expansion(int max_dim) {
1142  if (max_dim <= 1) return;
1143  clear_filtration(); // Drop the cache.
1144  dimension_ = max_dim;
1145  for (Dictionary_it root_it = root_.members_.begin();
1146  root_it != root_.members_.end(); ++root_it) {
1147  if (has_children(root_it)) {
1148  siblings_expansion(root_it->second.children(), max_dim - 1);
1149  }
1150  }
1151  dimension_ = max_dim - dimension_;
1152  }
1153 
1154  private:
1156  void siblings_expansion(Siblings * siblings, // must contain elements
1157  int k) {
1158  if (dimension_ > k) {
1159  dimension_ = k;
1160  }
1161  if (k == 0)
1162  return;
1163  Dictionary_it next = siblings->members().begin();
1164  ++next;
1165 
1166  thread_local std::vector<std::pair<Vertex_handle, Node> > inter;
1167  for (Dictionary_it s_h = siblings->members().begin();
1168  s_h != siblings->members().end(); ++s_h, ++next) {
1169  Simplex_handle root_sh = find_vertex(s_h->first);
1170  if (has_children(root_sh)) {
1171  intersection(
1172  inter, // output intersection
1173  next, // begin
1174  siblings->members().end(), // end
1175  root_sh->second.children()->members().begin(),
1176  root_sh->second.children()->members().end(),
1177  s_h->second.filtration());
1178  if (inter.size() != 0) {
1179  Siblings * new_sib = new Siblings(siblings, // oncles
1180  s_h->first, // parent
1181  inter); // boost::container::ordered_unique_range_t
1182  inter.clear();
1183  s_h->second.assign_children(new_sib);
1184  siblings_expansion(new_sib, k - 1);
1185  } else {
1186  // ensure the children property
1187  s_h->second.assign_children(siblings);
1188  inter.clear();
1189  }
1190  }
1191  }
1192  }
1193 
1196  static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection,
1197  Dictionary_it begin1, Dictionary_it end1,
1198  Dictionary_it begin2, Dictionary_it end2,
1199  Filtration_value filtration_) {
1200  if (begin1 == end1 || begin2 == end2)
1201  return; // ----->>
1202  while (true) {
1203  if (begin1->first == begin2->first) {
1204  Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_});
1205  intersection.emplace_back(begin1->first, Node(nullptr, filt));
1206  if (++begin1 == end1 || ++begin2 == end2)
1207  return; // ----->>
1208  } else if (begin1->first < begin2->first) {
1209  if (++begin1 == end1)
1210  return;
1211  } else /* begin1->first > begin2->first */ {
1212  if (++begin2 == end2)
1213  return; // ----->>
1214  }
1215  }
1216  }
1217 
1218  public:
1237  template< typename Blocker >
1238  void expansion_with_blockers(int max_dim, Blocker block_simplex) {
1239  // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1240  for (auto& simplex : boost::adaptors::reverse(root_.members())) {
1241  if (has_children(&simplex)) {
1242  siblings_expansion_with_blockers(simplex.second.children(), max_dim, max_dim - 1, block_simplex);
1243  }
1244  }
1245  }
1246 
1247  private:
1249  template< typename Blocker >
1250  void siblings_expansion_with_blockers(Siblings* siblings, int max_dim, int k, Blocker block_simplex) {
1251  if (dimension_ < max_dim - k) {
1252  dimension_ = max_dim - k;
1253  }
1254  if (k == 0)
1255  return;
1256  // No need to go deeper
1257  if (siblings->members().size() < 2)
1258  return;
1259  // Reverse loop starting before the last one for 'next' to be the last one
1260  for (auto simplex = siblings->members().rbegin() + 1; simplex != siblings->members().rend(); simplex++) {
1261  std::vector<std::pair<Vertex_handle, Node> > intersection;
1262  for(auto next = siblings->members().rbegin(); next != simplex; next++) {
1263  bool to_be_inserted = true;
1264  Filtration_value filt = simplex->second.filtration();
1265  // If all the boundaries are present, 'next' needs to be inserted
1266  for (Simplex_handle border : boundary_simplex_range(simplex)) {
1267  Simplex_handle border_child = find_child(border, next->first);
1268  if (border_child == null_simplex()) {
1269  to_be_inserted=false;
1270  break;
1271  }
1272  filt = (std::max)(filt, filtration(border_child));
1273  }
1274  if (to_be_inserted) {
1275  intersection.emplace_back(next->first, Node(nullptr, filt));
1276  }
1277  }
1278  if (intersection.size() != 0) {
1279  // Reverse the order to insert
1280  Siblings * new_sib = new Siblings(siblings, // oncles
1281  simplex->first, // parent
1282  boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t
1283  std::vector<Vertex_handle> blocked_new_sib_vertex_list;
1284  // As all intersections are inserted, we can call the blocker function on all new_sib members
1285  for (auto new_sib_member = new_sib->members().begin();
1286  new_sib_member != new_sib->members().end();
1287  new_sib_member++) {
1288  bool blocker_result = block_simplex(new_sib_member);
1289  // new_sib member has been blocked by the blocker function
1290  // add it to the list to be removed - do not perform it while looping on it
1291  if (blocker_result) {
1292  blocked_new_sib_vertex_list.push_back(new_sib_member->first);
1293  }
1294  }
1295  if (blocked_new_sib_vertex_list.size() == new_sib->members().size()) {
1296  // Specific case where all have to be deleted
1297  delete new_sib;
1298  // ensure the children property
1299  simplex->second.assign_children(siblings);
1300  } else {
1301  for (auto& blocked_new_sib_member : blocked_new_sib_vertex_list) {
1302  new_sib->members().erase(blocked_new_sib_member);
1303  }
1304  // ensure recursive call
1305  simplex->second.assign_children(new_sib);
1306  siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex);
1307  }
1308  } else {
1309  // ensure the children property
1310  simplex->second.assign_children(siblings);
1311  }
1312  }
1313  }
1314 
1315  /* \private Returns the Simplex_handle composed of the vertex list (from the Simplex_handle), plus the given
1316  * Vertex_handle if the Vertex_handle is found in the Simplex_handle children list.
1317  * Returns null_simplex() if it does not exist
1318  */
1319  Simplex_handle find_child(Simplex_handle sh, Vertex_handle vh) const {
1320  if (!has_children(sh))
1321  return null_simplex();
1322 
1323  Simplex_handle child = sh->second.children()->find(vh);
1324  // Specific case of boost::flat_map does not find, returns boost::flat_map::end()
1325  // in simplex tree we want a null_simplex()
1326  if (child == sh->second.children()->members().end())
1327  return null_simplex();
1328 
1329  return child;
1330  }
1331 
1332  public:
1339  void print_hasse(std::ostream& os) {
1340  os << num_simplices() << " " << std::endl;
1341  for (auto sh : filtration_simplex_range()) {
1342  os << dimension(sh) << " ";
1343  for (auto b_sh : boundary_simplex_range(sh)) {
1344  os << key(b_sh) << " ";
1345  }
1346  os << filtration(sh) << " \n";
1347  }
1348  }
1349 
1350  public:
1358  bool modified = false;
1359  // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1360  for (auto& simplex : boost::adaptors::reverse(root_.members())) {
1361  if (has_children(&simplex)) {
1362  modified |= rec_make_filtration_non_decreasing(simplex.second.children());
1363  }
1364  }
1365  if(modified)
1366  clear_filtration(); // Drop the cache.
1367  return modified;
1368  }
1369 
1370  private:
1375  bool rec_make_filtration_non_decreasing(Siblings * sib) {
1376  bool modified = false;
1377 
1378  // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1379  for (auto& simplex : boost::adaptors::reverse(sib->members())) {
1380  // Find the maximum filtration value in the border
1381  Boundary_simplex_range boundary = boundary_simplex_range(&simplex);
1382  Boundary_simplex_iterator max_border = std::max_element(std::begin(boundary), std::end(boundary),
1383  [](Simplex_handle sh1, Simplex_handle sh2) {
1384  return filtration(sh1) < filtration(sh2);
1385  });
1386 
1387  Filtration_value max_filt_border_value = filtration(*max_border);
1388  // Replacing if(f<max) with if(!(f>=max)) would mean that if f is NaN, we replace it with the max of the children.
1389  // That seems more useful than keeping NaN.
1390  if (!(simplex.second.filtration() >= max_filt_border_value)) {
1391  // Store the filtration modification information
1392  modified = true;
1393  simplex.second.assign_filtration(max_filt_border_value);
1394  }
1395  if (has_children(&simplex)) {
1396  modified |= rec_make_filtration_non_decreasing(simplex.second.children());
1397  }
1398  }
1399  // Make the modified information to be traced by upper call
1400  return modified;
1401  }
1402 
1403  public:
1411  bool prune_above_filtration(Filtration_value filtration) {
1412  bool modified = rec_prune_above_filtration(root(), filtration);
1413  if(modified)
1414  clear_filtration(); // Drop the cache.
1415  return modified;
1416  }
1417 
1418  private:
1419  bool rec_prune_above_filtration(Siblings* sib, Filtration_value filt) {
1420  auto&& list = sib->members();
1421  auto last = std::remove_if(list.begin(), list.end(), [this,filt](Dit_value_t& simplex) {
1422  if (simplex.second.filtration() <= filt) return false;
1423  if (has_children(&simplex)) rec_delete(simplex.second.children());
1424  // dimension may need to be lowered
1425  dimension_to_be_lowered_ = true;
1426  return true;
1427  });
1428 
1429  bool modified = (last != list.end());
1430  if (last == list.begin() && sib != root()) {
1431  // Removing the whole siblings, parent becomes a leaf.
1432  sib->oncles()->members()[sib->parent()].assign_children(sib->oncles());
1433  delete sib;
1434  // dimension may need to be lowered
1435  dimension_to_be_lowered_ = true;
1436  return true;
1437  } else {
1438  // Keeping some elements of siblings. Remove the others, and recurse in the remaining ones.
1439  list.erase(last, list.end());
1440  for (auto&& simplex : list)
1441  if (has_children(&simplex))
1442  modified |= rec_prune_above_filtration(simplex.second.children(), filt);
1443  }
1444  return modified;
1445  }
1446 
1447  private:
1453  bool lower_upper_bound_dimension() {
1454  // reset automatic detection to recompute
1455  dimension_to_be_lowered_ = false;
1456  int new_dimension = -1;
1457  // Browse the tree from the left to the right as higher dimension cells are more likely on the left part of the tree
1458  for (Simplex_handle sh : complex_simplex_range()) {
1459 #ifdef DEBUG_TRACES
1460  for (auto vertex : simplex_vertex_range(sh)) {
1461  std::clog << " " << vertex;
1462  }
1463  std::clog << std::endl;
1464 #endif // DEBUG_TRACES
1465 
1466  int sh_dimension = dimension(sh);
1467  if (sh_dimension >= dimension_)
1468  // Stop browsing as soon as the dimension is reached, no need to go furter
1469  return false;
1470  new_dimension = (std::max)(new_dimension, sh_dimension);
1471  }
1472  dimension_ = new_dimension;
1473  return true;
1474  }
1475 
1476 
1477  public:
1486  void remove_maximal_simplex(Simplex_handle sh) {
1487  // Guarantee the simplex has no children
1488  GUDHI_CHECK(!has_children(sh),
1489  std::invalid_argument("Simplex_tree::remove_maximal_simplex - argument has children"));
1490 
1491  // Simplex is a leaf, it means the child is the Siblings owning the leaf
1492  Siblings* child = sh->second.children();
1493 
1494  if ((child->size() > 1) || (child == root())) {
1495  // Not alone, just remove it from members
1496  // Special case when child is the root of the simplex tree, just remove it from members
1497  child->erase(sh);
1498  } else {
1499  // Sibling is emptied : must be deleted, and its parent must point on his own Sibling
1500  child->oncles()->members().at(child->parent()).assign_children(child->oncles());
1501  delete child;
1502  // dimension may need to be lowered
1503  dimension_to_be_lowered_ = true;
1504  }
1505  }
1506 
1523  std::pair<Filtration_value, Extended_simplex_type> decode_extended_filtration(Filtration_value f, const Extended_filtration_data& efd){
1524  std::pair<Filtration_value, Extended_simplex_type> p;
1525  Filtration_value minval = efd.minval;
1526  Filtration_value maxval = efd.maxval;
1527  if (f >= -2 && f <= -1){
1528  p.first = minval + (maxval-minval)*(f + 2); p.second = Extended_simplex_type::UP;
1529  }
1530  else if (f >= 1 && f <= 2){
1531  p.first = minval - (maxval-minval)*(f - 2); p.second = Extended_simplex_type::DOWN;
1532  }
1533  else{
1534  p.first = std::numeric_limits<Filtration_value>::quiet_NaN(); p.second = Extended_simplex_type::EXTRA;
1535  }
1536  return p;
1537  };
1538 
1552  Extended_filtration_data extend_filtration() {
1553  clear_filtration(); // Drop the cache.
1554 
1555  // Compute maximum and minimum of filtration values
1556  Vertex_handle maxvert = std::numeric_limits<Vertex_handle>::min();
1557  Filtration_value minval = std::numeric_limits<Filtration_value>::infinity();
1558  Filtration_value maxval = -std::numeric_limits<Filtration_value>::infinity();
1559  for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh){
1560  Filtration_value f = this->filtration(sh);
1561  minval = std::min(minval, f);
1562  maxval = std::max(maxval, f);
1563  maxvert = std::max(sh->first, maxvert);
1564  }
1565 
1566  GUDHI_CHECK(maxvert < std::numeric_limits<Vertex_handle>::max(), std::invalid_argument("Simplex_tree contains a vertex with the largest Vertex_handle"));
1567  maxvert += 1;
1568 
1569  Simplex_tree st_copy = *this;
1570 
1571  // Add point for coning the simplicial complex
1572  this->insert_simplex({maxvert}, -3);
1573 
1574  // For each simplex
1575  std::vector<Vertex_handle> vr;
1576  for (auto sh_copy : st_copy.complex_simplex_range()){
1577 
1578  // Locate simplex
1579  vr.clear();
1580  for (auto vh : st_copy.simplex_vertex_range(sh_copy)){
1581  vr.push_back(vh);
1582  }
1583  auto sh = this->find(vr);
1584 
1585  // Create cone on simplex
1586  vr.push_back(maxvert);
1587  if (this->dimension(sh) == 0){
1588  Filtration_value v = this->filtration(sh);
1589  Filtration_value scaled_v = (v-minval)/(maxval-minval);
1590  // Assign ascending value between -2 and -1 to vertex
1591  this->assign_filtration(sh, -2 + scaled_v);
1592  // Assign descending value between 1 and 2 to cone on vertex
1593  this->insert_simplex(vr, 2 - scaled_v);
1594  }
1595  else{
1596  // Assign value -3 to simplex and cone on simplex
1597  this->assign_filtration(sh, -3);
1598  this->insert_simplex(vr, -3);
1599  }
1600  }
1601 
1602  // Automatically assign good values for simplices
1603  this->make_filtration_non_decreasing();
1604 
1605  // Return the filtration data
1606  Extended_filtration_data efd(minval, maxval);
1607  return efd;
1608  }
1609 
1614  Vertex_handle vertex_with_same_filtration(Simplex_handle sh) {
1615  auto filt = filtration_(sh);
1616  for(auto v : simplex_vertex_range(sh))
1617  if(filtration_(find_vertex(v)) == filt)
1618  return v;
1619  return null_vertex();
1620  }
1621 
1628  Simplex_handle edge_with_same_filtration(Simplex_handle sh) {
1629  // See issue #251 for potential speed improvements.
1630  auto&& vertices = simplex_vertex_range(sh); // vertices in decreasing order
1631  auto end = std::end(vertices);
1632  auto vi = std::begin(vertices);
1633  GUDHI_CHECK(vi != end, "empty simplex");
1634  auto v0 = *vi;
1635  ++vi;
1636  GUDHI_CHECK(vi != end, "simplex of dimension 0");
1637  if(std::next(vi) == end) return sh; // shortcut for dimension 1
1638  boost::container::static_vector<Vertex_handle, 40> suffix;
1639  suffix.push_back(v0);
1640  auto filt = filtration_(sh);
1641  do
1642  {
1643  Vertex_handle v = *vi;
1644  auto&& children1 = find_vertex(v)->second.children()->members_;
1645  for(auto w : suffix){
1646  // Can we take advantage of the fact that suffix is ordered?
1647  Simplex_handle s = children1.find(w);
1648  if(filtration_(s) == filt)
1649  return s;
1650  }
1651  suffix.push_back(v);
1652  }
1653  while(++vi != end);
1654  return null_simplex();
1655  }
1656 
1661  Simplex_handle minimal_simplex_with_same_filtration(Simplex_handle sh) {
1662  auto filt = filtration_(sh);
1663  // Naive implementation, it can be sped up.
1664  for(auto b : boundary_simplex_range(sh))
1665  if(filtration_(b) == filt)
1666  return minimal_simplex_with_same_filtration(b);
1667  return sh; // None of its faces has the same filtration.
1668  }
1669 
1670  public:
1679  void reset_filtration(Filtration_value filt_value, int min_dim = 0) {
1680  rec_reset_filtration(&root_, filt_value, min_dim);
1681  clear_filtration(); // Drop the cache.
1682  }
1683 
1684  private:
1690  void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int min_depth) {
1691  for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
1692  if (min_depth <= 0) {
1693  sh->second.assign_filtration(filt_value);
1694  }
1695  if (has_children(sh)) {
1696  rec_reset_filtration(sh->second.children(), filt_value, min_depth - 1);
1697  }
1698  }
1699  }
1700 
1701  private:
1702  Vertex_handle null_vertex_;
1705  Siblings root_;
1707  std::vector<Simplex_handle> filtration_vect_;
1709  int dimension_;
1710  bool dimension_to_be_lowered_ = false;
1711 };
1712 
1713 // Print a Simplex_tree in os.
1714 template<typename...T>
1715 std::ostream& operator<<(std::ostream & os, Simplex_tree<T...> & st) {
1716  for (auto sh : st.filtration_simplex_range()) {
1717  os << st.dimension(sh) << " ";
1718  for (auto v : st.simplex_vertex_range(sh)) {
1719  os << v << " ";
1720  }
1721  os << st.filtration(sh) << "\n"; // TODO(VR): why adding the key ?? not read ?? << " " << st.key(sh) << " \n";
1722  }
1723  return os;
1724 }
1725 
1726 template<typename...T>
1727 std::istream& operator>>(std::istream & is, Simplex_tree<T...> & st) {
1728  typedef Simplex_tree<T...> ST;
1729  std::vector<typename ST::Vertex_handle> simplex;
1730  typename ST::Filtration_value fil;
1731  int max_dim = -1;
1732  while (read_simplex(is, simplex, fil)) {
1733  // read all simplices in the file as a list of vertices
1734  // Warning : simplex_size needs to be casted in int - Can be 0
1735  int dim = static_cast<int> (simplex.size() - 1);
1736  if (max_dim < dim) {
1737  max_dim = dim;
1738  }
1739  // insert every simplex in the simplex tree
1740  st.insert_simplex(simplex, fil);
1741  simplex.clear();
1742  }
1743  st.set_dimension(max_dim);
1744 
1745  return is;
1746 }
1747 
1753  typedef linear_indexing_tag Indexing_tag;
1754  typedef int Vertex_handle;
1755  typedef double Filtration_value;
1756  typedef std::uint32_t Simplex_key;
1757  static const bool store_key = true;
1758  static const bool store_filtration = true;
1759  static const bool contiguous_vertices = false;
1760 };
1761 
1769  typedef linear_indexing_tag Indexing_tag;
1770  typedef int Vertex_handle;
1771  typedef float Filtration_value;
1772  typedef std::uint32_t Simplex_key;
1773  static const bool store_key = true;
1774  static const bool store_filtration = true;
1775  static const bool contiguous_vertices = true;
1776 };
1777  // end defgroup simplex_tree
1779 
1780 } // namespace Gudhi
1781 
1782 #endif // SIMPLEX_TREE_H_
Simplex_tree_skeleton_simplex_iterator< Simplex_tree > Skeleton_simplex_iterator
Iterator over the simplices of the skeleton of the simplicial complex, for a given dimension...
Definition: Simplex_tree.h:200
Dictionary::iterator Simplex_handle
Handle type to a simplex contained in the simplicial complex represented by the simplex tree...
Definition: Simplex_tree.h:149
bool prune_above_filtration(Filtration_value filtration)
Prune above filtration value given as parameter.
Definition: Simplex_tree.h:1411
void expansion(int max_dim)
Expands the Simplex_tree containing only its one skeleton until dimension max_dim.
Definition: Simplex_tree.h:1141
Filtration_simplex_range::const_iterator Filtration_simplex_iterator
Iterator over the simplices of the simplicial complex, ordered by the filtration. ...
Definition: Simplex_tree.h:209
Tag for a linear ordering of simplices.
Definition: indexing_tag.h:20
Simplex Tree data structure for representing simplicial complexes.
Definition: Simplex_tree.h:75
void maybe_initialize_filtration()
Initializes the filtration cache if it isn&#39;t initialized yet.
Definition: Simplex_tree.h:910
std::pair< Simplex_handle, bool > insert_simplex_and_subfaces(const InputVertexRange &Nsimplex, Filtration_value filtration=0)
Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of Vertex_handles...
Definition: Simplex_tree.h:781
void assign_key(Simplex_handle sh, Simplex_key key)
Assign a value &#39;key&#39; to the key of the simplex represented by the Simplex_handle &#39;sh&#39;.
Definition: Simplex_tree.h:842
bool read_simplex(std::istream &in_, std::vector< Vertex_handle > &simplex, Filtration_value &fil)
Read a face from a file.
Definition: reader_utils.h:158
bool operator==(Simplex_tree &st2)
Checks if two simplex trees are equal.
Definition: Simplex_tree.h:446
Simplex_handle edge_with_same_filtration(Simplex_handle sh)
Returns an edge of sh that has the same filtration value as sh if it exists, and null_simplex() other...
Definition: Simplex_tree.h:1628
Concept describing an indexing scheme (see FilteredComplex) for applying continuous maps to a cell co...
Definition: IndexingTag.h:18
static Simplex_key key(Simplex_handle sh)
Returns the key associated to a simplex.
Definition: Simplex_tree.h:492
static Simplex_handle null_simplex()
Returns a Simplex_handle different from all Simplex_handles associated to the simplices in the simpli...
Definition: Simplex_tree.h:530
static Siblings * self_siblings(SimplexHandle sh)
Definition: Simplex_tree.h:856
boost::iterator_range< Complex_vertex_iterator > Complex_vertex_range
Range over the vertices of the simplicial complex.
Definition: Simplex_tree.h:175
Vertex_handle null_vertex() const
Returns a Vertex_handle different from all Vertex_handles associated to the vertices of the simplicia...
Definition: Simplex_tree.h:541
Simplex_tree_simplex_vertex_iterator< Simplex_tree > Simplex_vertex_iterator
Iterator over the vertices of a simplex.
Definition: Simplex_tree.h:179
Extended_filtration_data extend_filtration()
Extend filtration for computing extended persistence. This function only uses the filtration values a...
Definition: Simplex_tree.h:1552
Definition: SimplicialComplexForAlpha.h:14
void print_hasse(std::ostream &os)
Write the hasse diagram of the simplicial complex in os.
Definition: Simplex_tree.h:1339
Key type used as simplex identifier.
Definition: SimplexKey.h:15
Siblings * root()
Definition: Simplex_tree.h:865
std::pair< Filtration_value, Extended_simplex_type > decode_extended_filtration(Filtration_value f, const Extended_filtration_data &efd)
Retrieve the original filtration value for a given simplex in the Simplex_tree. Since the computation...
Definition: Simplex_tree.h:1523
Options::Simplex_key Simplex_key
Key associated to each simplex.
Definition: Simplex_tree.h:86
bool operator!=(Simplex_tree &st2)
Checks if two simplex trees are different.
Definition: Simplex_tree.h:454
bool make_filtration_non_decreasing()
This function ensures that each simplex has a higher filtration value than its faces by increasing th...
Definition: Simplex_tree.h:1357
std::vector< Simplex_handle > Filtration_simplex_range
Range over the simplices of the simplicial complex, ordered by the filtration.
Definition: Simplex_tree.h:205
int dimension()
Returns the dimension of the simplicial complex.
Definition: Simplex_tree.h:593
Filtration_simplex_range const & filtration_simplex_range(Indexing_tag=Indexing_tag())
Returns a range over the simplices of the simplicial complex, in the order of the filtration...
Definition: Simplex_tree.h:262
void initialize_filtration()
Initializes the filtration cache, i.e. sorts the simplices according to their order in the filtration...
Definition: Simplex_tree.h:886
Simplex_handle find(const InputVertexRange &s)
Given a range of Vertex_handles, returns the Simplex_handle of the simplex in the simplicial complex ...
Definition: Simplex_tree.h:615
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20
Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension)
Compute the cofaces of a n simplex.
Definition: Simplex_tree.h:993
Complex_simplex_range complex_simplex_range()
Returns a range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:228
Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) const
Returns a range over the vertices of a simplex.
Definition: Simplex_tree.h:273
Concept of the template parameter for the class Gudhi::Simplex_tree<SimplexTreeOptions>.
Definition: SimplexTreeOptions.h:15
size_t num_vertices() const
Returns the number of vertices in the complex.
Definition: Simplex_tree.h:546
void assign_filtration(Simplex_handle sh, Filtration_value fv)
Sets the filtration value of a simplex.
Definition: Simplex_tree.h:520
std::pair< Simplex_handle, Simplex_handle > endpoints(Simplex_handle sh)
Definition: Simplex_tree.h:849
Boundary_simplex_range boundary_simplex_range(SimplexHandle sh)
Returns a range over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:294
void clear_filtration()
Clears the filtration cache produced by initialize_filtration().
Definition: Simplex_tree.h:919
Complex_vertex_range complex_vertex_range()
Returns a range over the vertices of the simplicial complex. The order is increasing according to < o...
Definition: Simplex_tree.h:217
Options::Vertex_handle Vertex_handle
Type for the vertex handle.
Definition: Simplex_tree.h:90
Simplex_tree(Simplex_tree &&complex_source)
User-defined move constructor relocates the whole tree structure.
Definition: Simplex_tree.h:321
Simplex_tree & operator=(Simplex_tree &&complex_source)
User-defined move assignment relocates the whole tree structure.
Definition: Simplex_tree.h:355
Vertex_handle vertex_with_same_filtration(Simplex_handle sh)
Returns a vertex of sh that has the same filtration value as sh if it exists, and null_vertex() other...
Definition: Simplex_tree.h:1614
Skeleton_simplex_range skeleton_simplex_range(int dim)
Returns a range over the simplices of the dim-skeleton of the simplicial complex. ...
Definition: Simplex_tree.h:242
boost::iterator_range< Boundary_simplex_iterator > Boundary_simplex_range
Range over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:189
bool has_children(SimplexHandle sh) const
Returns true if the node in the simplex tree pointed by sh has children.
Definition: Simplex_tree.h:602
Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex)
Compute the star of a n simplex.
Definition: Simplex_tree.h:982
void set_dimension(int dimension)
Set a dimension for the simplicial complex.
Definition: Simplex_tree.h:873
int upper_bound_dimension() const
Returns an upper bound on the dimension of the simplicial complex.
Definition: Simplex_tree.h:585
int dimension(Simplex_handle sh)
Returns the dimension of a simplex.
Definition: Simplex_tree.h:574
static Simplex_key null_key()
Returns a fixed number not in the interval [0, num_simplices()).
Definition: Simplex_tree.h:535
static Filtration_value filtration(Simplex_handle sh)
Returns the filtration value of a simplex.
Definition: Simplex_tree.h:509
void reset_filtration(Filtration_value filt_value, int min_dim=0)
This function resets the filtration value of all the simplices of dimension at least min_dim...
Definition: Simplex_tree.h:1679
Definition: Simplex_tree.h:1768
Simplex_tree(const Simplex_tree &complex_source)
User-defined copy constructor reproduces the whole tree structure.
Definition: Simplex_tree.h:311
Handle type for the vertices of a cell complex.
Definition: VertexHandle.h:15
boost::transform_iterator< return_first, Dictionary_it > Complex_vertex_iterator
Iterator over the vertices of the simplicial complex.
Definition: Simplex_tree.h:173
~Simplex_tree()
Destructor; deallocates the whole tree structure.
Definition: Simplex_tree.h:333
void remove_maximal_simplex(Simplex_handle sh)
Remove a maximal simplex.
Definition: Simplex_tree.h:1486
size_t num_simplices()
returns the number of simplices in the simplex_tree.
Definition: Simplex_tree.h:552
boost::iterator_range< Complex_simplex_iterator > Complex_simplex_range
Range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:195
Options::Filtration_value Filtration_value
Type for the value of the filtration function.
Definition: Simplex_tree.h:82
Simplex_tree()
Constructs an empty simplex tree.
Definition: Simplex_tree.h:304
Extended simplex type data structure for representing the type of simplices in an extended filtration...
Simplex_tree_boundary_simplex_iterator< Simplex_tree > Boundary_simplex_iterator
Iterator over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:187
boost::iterator_range< Skeleton_simplex_iterator > Skeleton_simplex_range
Range over the simplices of the skeleton of the simplicial complex, for a given dimension.
Definition: Simplex_tree.h:203
Simplex_tree_complex_simplex_iterator< Simplex_tree > Complex_simplex_iterator
Iterator over the simplices of the simplicial complex.
Definition: Simplex_tree.h:193
void insert_graph(const OneSkeletonGraph &skel_graph)
Inserts a 1-skeleton in an empty Simplex_tree.
Definition: Simplex_tree.h:1080
Simplex_handle simplex(Simplex_key idx) const
Returns the simplex that has index idx in the filtration.
Definition: Simplex_tree.h:500
Graph simplicial complex methods.
Simplex_handle minimal_simplex_with_same_filtration(Simplex_handle sh)
Returns a minimal face of sh that has the same filtration value as sh.
Definition: Simplex_tree.h:1661
This file includes common file reader for GUDHI.
boost::iterator_range< Simplex_vertex_iterator > Simplex_vertex_range
Range over the vertices of a simplex.
Definition: Simplex_tree.h:181
std::pair< Simplex_handle, bool > insert_simplex(const InputVertexRange &simplex, Filtration_value filtration=0)
Insert a simplex, represented by a range of Vertex_handles, in the simplicial complex.
Definition: Simplex_tree.h:752
void expansion_with_blockers(int max_dim, Blocker block_simplex)
Expands a simplex tree containing only a graph. Simplices corresponding to cliques in the graph are a...
Definition: Simplex_tree.h:1238
std::vector< Simplex_handle > Cofaces_simplex_range
Range over the cofaces of a simplex.
Definition: Simplex_tree.h:183
GUDHI  Version 3.4.1  - C++ library for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding.  - Copyright : MIT Generated on Fri Jan 22 2021 09:41:15 for GUDHI by Doxygen 1.8.13