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  * - 2023/02 Vincent Rouvreau: Add de/serialize methods for pickle feature
9  * - 2023/07 Clément Maria: Option to link all simplex tree nodes with same label in an intrusive list
10  * - 2023/05 Clément Maria: Edge insertion method for flag complexes
11  * - 2023/05 Hannah Schreiber: Factorization of expansion methods
12  * - 2023/08 Hannah Schreiber (& Clément Maria): Add possibility of stable simplex handles.
13  * - YYYY/MM Author: Description of the modification
14  */
15 
16 #ifndef SIMPLEX_TREE_H_
17 #define SIMPLEX_TREE_H_
18 
19 #include <gudhi/Simplex_tree/simplex_tree_options.h>
20 #include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h>
21 #include <gudhi/Simplex_tree/Simplex_tree_siblings.h>
22 #include <gudhi/Simplex_tree/Simplex_tree_iterators.h>
23 #include <gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h>
24 #include <gudhi/Simplex_tree/serialization_utils.h> // for Gudhi::simplex_tree::de/serialize_trivial
25 #include <gudhi/Simplex_tree/hooks_simplex_base.h>
26 
27 #include <gudhi/reader_utils.h>
29 #include <gudhi/Debug_utils.h>
30 
31 #include <boost/container/map.hpp>
32 #include <boost/container/flat_map.hpp>
33 #include <boost/iterator/transform_iterator.hpp>
34 #include <boost/graph/adjacency_list.hpp>
35 #include <boost/range/adaptor/reversed.hpp>
36 #include <boost/range/adaptor/transformed.hpp>
37 #include <boost/range/size.hpp>
38 #include <boost/container/static_vector.hpp>
39 #include <boost/range/adaptors.hpp>
40 
41 #include <boost/intrusive/list.hpp>
42 #include <boost/intrusive/parent_from_member.hpp>
43 #include <cstddef>
44 
45 #ifdef GUDHI_USE_TBB
46 #include <tbb/parallel_sort.h>
47 #endif
48 
49 #include <utility> // for std::move
50 #include <vector>
51 #include <functional> // for greater<>
52 #include <stdexcept>
53 #include <limits> // Inf
54 #include <initializer_list>
55 #include <algorithm> // for std::max
56 #include <iterator> // for std::distance
57 #include <type_traits> // for std::conditional
58 #include <unordered_map>
59 #include <iterator> // for std::prev
60 
61 namespace Gudhi {
62 
79 enum class Extended_simplex_type {UP, DOWN, EXTRA};
80 
94 template<typename SimplexTreeOptions = Simplex_tree_options_default>
95 class Simplex_tree {
96  public:
98  typedef typename Options::Indexing_tag Indexing_tag;
111 
112  /* Type of node in the simplex tree. */
114  /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
115  // Note: this wastes space when Vertex_handle is 32 bits and Node is aligned on 64 bits. It would be better to use a
116  // flat_set (with our own comparator) where we can control the layout of the struct (put Vertex_handle and
117  // Simplex_key next to each other).
118  typedef typename boost::container::flat_map<Vertex_handle, Node> flat_map;
119  //Dictionary::iterator remain valid under insertions and deletions,
120  //necessary e.g. when computing oscillating rips zigzag filtrations.
121  typedef typename boost::container::map<Vertex_handle, Node> map;
122  typedef typename std::conditional<Options::stable_simplex_handles,
123  map,
124  flat_map>::type Dictionary;
125 
128 
129 
130 
131  struct Key_simplex_base_real {
132  Key_simplex_base_real() : key_(-1) {}
133  void assign_key(Simplex_key k) { key_ = k; }
134  Simplex_key key() const { return key_; }
135  private:
136  Simplex_key key_;
137  };
138  struct Key_simplex_base_dummy {
139  Key_simplex_base_dummy() {}
140  // Undefined so it will not link
141  void assign_key(Simplex_key);
142  Simplex_key key() const;
143  };
144  struct Extended_filtration_data {
145  Filtration_value minval;
146  Filtration_value maxval;
147  Extended_filtration_data(){}
148  Extended_filtration_data(Filtration_value vmin, Filtration_value vmax): minval(vmin), maxval(vmax) {}
149  };
150  typedef typename std::conditional<Options::store_key, Key_simplex_base_real, Key_simplex_base_dummy>::type
151  Key_simplex_base;
152 
153  struct Filtration_simplex_base_real {
154  Filtration_simplex_base_real() : filt_(0) {}
155  void assign_filtration(Filtration_value f) { filt_ = f; }
156  Filtration_value filtration() const { return filt_; }
157  private:
158  Filtration_value filt_;
159  };
160  struct Filtration_simplex_base_dummy {
161  Filtration_simplex_base_dummy() {}
162  void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); }
163  Filtration_value filtration() const { return 0; }
164  };
165  typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real,
166  Filtration_simplex_base_dummy>::type Filtration_simplex_base;
167 
168  public:
175  typedef typename Dictionary::iterator Simplex_handle;
176 
177  private:
178  typedef typename Dictionary::iterator Dictionary_it;
179  typedef typename Dictionary_it::value_type Dit_value_t;
180 
181  struct return_first {
182  Vertex_handle operator()(const Dit_value_t& p_sh) const {
183  return p_sh.first;
184  }
185  };
186 
187  private:
194  using Optimized_star_simplex_iterator = Simplex_tree_optimized_star_simplex_iterator<Simplex_tree>;
196  using Optimized_star_simplex_range = boost::iterator_range<Optimized_star_simplex_iterator>;
197 
198  class Fast_cofaces_predicate {
199  Simplex_tree* st_;
200  int codim_;
201  int dim_;
202  public:
203  Fast_cofaces_predicate(Simplex_tree* st, int codim, int dim)
204  : st_(st), codim_(codim), dim_(codim + dim) {}
205  bool operator()( const Simplex_handle iter ) const {
206  if (codim_ == 0)
207  // Always true for a star
208  return true;
209  // Specific coface case
210  return dim_ == st_->dimension(iter);
211  }
212  };
213 
214  // WARNING: this is safe only because boost::filtered_range is containing a copy of begin and end iterator.
215  // This would not be safe if it was containing a pointer to a range (maybe the case for std::views)
216  using Optimized_cofaces_simplex_filtered_range = boost::filtered_range<Fast_cofaces_predicate,
217  Optimized_star_simplex_range>;
218 
219 
222  static constexpr int max_dimension() { return 40; }
223  public:
235  typedef boost::transform_iterator<return_first, Dictionary_it> Complex_vertex_iterator;
237  typedef boost::iterator_range<Complex_vertex_iterator> Complex_vertex_range;
243  typedef boost::iterator_range<Simplex_vertex_iterator> Simplex_vertex_range;
245  typedef typename std::conditional<Options::link_nodes_by_label,
246  Optimized_cofaces_simplex_filtered_range, // faster implem
247  std::vector<Simplex_handle>>::type Cofaces_simplex_range;
248 
252  using Static_vertex_vector = boost::container::static_vector<Vertex_handle, max_dimension()>;
253 
259  typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range;
265  typedef boost::iterator_range<Boundary_opposite_vertex_simplex_iterator> Boundary_opposite_vertex_simplex_range;
271  typedef boost::iterator_range<Complex_simplex_iterator> Complex_simplex_range;
279  typedef boost::iterator_range<Skeleton_simplex_iterator> Skeleton_simplex_range;
281  typedef std::vector<Simplex_handle> Filtration_simplex_range;
285  typedef typename Filtration_simplex_range::const_iterator Filtration_simplex_iterator;
286 
287  /* @} */ // end name range and iterator types
294  return Complex_vertex_range(
295  boost::make_transform_iterator(root_.members_.begin(), return_first()),
296  boost::make_transform_iterator(root_.members_.end(), return_first()));
297  }
298 
307  }
308 
321  }
322 
340  return filtration_vect_;
341  }
342 
350  GUDHI_CHECK(sh != null_simplex(), "empty simplex");
353  }
354 
369  template<class SimplexHandle>
373  }
374 
386  template<class SimplexHandle>
390  }
391  // end range and iterator methods
398  : null_vertex_(-1),
399  root_(nullptr, null_vertex_),
400  filtration_vect_(),
401  dimension_(-1) { }
402 
404  Simplex_tree(const Simplex_tree& complex_source) {
405 #ifdef DEBUG_TRACES
406  std::clog << "Simplex_tree copy constructor" << std::endl;
407 #endif // DEBUG_TRACES
408  copy_from(complex_source);
409  }
410 
414  Simplex_tree(Simplex_tree && complex_source) {
415 #ifdef DEBUG_TRACES
416  std::clog << "Simplex_tree move constructor" << std::endl;
417 #endif // DEBUG_TRACES
418  move_from(complex_source);
419 
420  // just need to set dimension_ on source to make it available again
421  // (filtration_vect_ and members are already set from the move)
422  complex_source.dimension_ = -1;
423  }
424 
427  root_members_recursive_deletion();
428  }
429 
431  Simplex_tree& operator= (const Simplex_tree& complex_source) {
432 #ifdef DEBUG_TRACES
433  std::clog << "Simplex_tree copy assignment" << std::endl;
434 #endif // DEBUG_TRACES
435  // Self-assignment detection
436  if (&complex_source != this) {
437  // We start by deleting root_ if not empty
438  root_members_recursive_deletion();
439 
440  copy_from(complex_source);
441  }
442  return *this;
443  }
444 
448  Simplex_tree& operator=(Simplex_tree&& complex_source) {
449 #ifdef DEBUG_TRACES
450  std::clog << "Simplex_tree move assignment" << std::endl;
451 #endif // DEBUG_TRACES
452  // Self-assignment detection
453  if (&complex_source != this) {
454  // root_ deletion in case it was not empty
455  root_members_recursive_deletion();
456 
457  move_from(complex_source);
458  }
459  return *this;
460  } // end constructor/destructor
462 
463  private:
464  // Copy from complex_source to "this"
465  void copy_from(const Simplex_tree& complex_source) {
466  null_vertex_ = complex_source.null_vertex_;
467  filtration_vect_.clear();
468  dimension_ = complex_source.dimension_;
469  auto root_source = complex_source.root_;
470 
471  // root members copy
472  root_.members() = Dictionary(boost::container::ordered_unique_range, root_source.members().begin(), root_source.members().end());
473  // Needs to reassign children
474  for (auto& map_el : root_.members()) {
475  map_el.second.assign_children(&root_);
476  }
477  rec_copy(&root_, &root_source);
478  }
479 
481  void rec_copy(Siblings *sib, Siblings *sib_source) {
482  for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin();
483  sh != sib->members().end(); ++sh, ++sh_source) {
484  update_simplex_tree_after_node_insertion(sh);
485  if (has_children(sh_source)) {
486  Siblings * newsib = new Siblings(sib, sh_source->first);
487  if constexpr (!Options::stable_simplex_handles) {
488  newsib->members_.reserve(sh_source->second.children()->members().size());
489  }
490  for (auto & child : sh_source->second.children()->members())
491  newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(newsib, child.second.filtration()));
492  rec_copy(newsib, sh_source->second.children());
493  sh->second.assign_children(newsib);
494  }
495  }
496  }
497 
498  // Move from complex_source to "this"
499  void move_from(Simplex_tree& complex_source) {
500  null_vertex_ = std::move(complex_source.null_vertex_);
501  root_ = std::move(complex_source.root_);
502  filtration_vect_ = std::move(complex_source.filtration_vect_);
503  dimension_ = complex_source.dimension_;
504  if constexpr (Options::link_nodes_by_label) {
505  nodes_label_to_list_.swap(complex_source.nodes_label_to_list_);
506  }
507  // Need to update root members (children->oncles and children need to point on the new root pointer)
508  for (auto& map_el : root_.members()) {
509  if (map_el.second.children() != &(complex_source.root_)) {
510  // reset children->oncles with the moved root_ pointer value
511  map_el.second.children()->oncles_ = &root_;
512  } else {
513  // if simplex is of dimension 0, oncles_ shall be nullptr
514  GUDHI_CHECK(map_el.second.children()->oncles_ == nullptr,
515  std::invalid_argument("Simplex_tree move constructor from an invalid Simplex_tree"));
516  // and children points on root_ - to be moved
517  map_el.second.assign_children(&root_);
518  }
519  }
520  }
521 
522  // delete all root_.members() recursively
523  void root_members_recursive_deletion() {
524  for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh) {
525  if (has_children(sh)) {
526  rec_delete(sh->second.children());
527  }
528  }
529  root_.members().clear();
530  }
531 
532  // Recursive deletion
533  void rec_delete(Siblings * sib) {
534  for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
535  if (has_children(sh)) {
536  rec_delete(sh->second.children());
537  }
538  }
539  delete sib;
540  }
541 
542  public:
543  template<typename> friend class Simplex_tree;
544 
546  template<class OtherSimplexTreeOptions>
548  if ((null_vertex_ != st2.null_vertex_) ||
549  (dimension_ != st2.dimension_ && !dimension_to_be_lowered_ && !st2.dimension_to_be_lowered_))
550  return false;
551  return rec_equal(&root_, &st2.root_);
552  }
553 
555  template<class OtherSimplexTreeOptions>
557  return (!(*this == st2));
558  }
559 
560  private:
562  template<class OtherSiblings>
563  bool rec_equal(Siblings* s1, OtherSiblings* s2) {
564  if (s1->members().size() != s2->members().size())
565  return false;
566  auto sh2 = s2->members().begin();
567  for (auto sh1 = s1->members().begin();
568  (sh1 != s1->members().end() && sh2 != s2->members().end());
569  ++sh1, ++sh2) {
570  if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration())
571  return false;
572  if (has_children(sh1) != has_children(sh2))
573  return false;
574  // Recursivity on children only if both have children
575  else if (has_children(sh1))
576  if (!rec_equal(sh1->second.children(), sh2->second.children()))
577  return false;
578  }
579  return true;
580  }
581 
586  static Filtration_value filtration_(Simplex_handle sh) {
587  GUDHI_CHECK (sh != null_simplex(), "null simplex");
588  return sh->second.filtration();
589  }
590 
591  public:
598  return sh->second.key();
599  }
600 
606  return filtration_vect_[idx];
607  }
608 
615  if (sh != null_simplex()) {
616  return sh->second.filtration();
617  } else {
618  return std::numeric_limits<Filtration_value>::infinity();
619  }
620  }
621 
626  GUDHI_CHECK(sh != null_simplex(),
627  std::invalid_argument("Simplex_tree::assign_filtration - cannot assign filtration on null_simplex"));
628  sh->second.assign_filtration(fv);
629  }
630 
636  return Dictionary_it();
637  }
638 
641  return -1;
642  }
643 
647  return null_vertex_;
648  }
649 
651  size_t num_vertices() const {
652  return root_.members_.size();
653  }
654 
656  bool is_empty() const {
657  return root_.members_.empty();
658  }
659 
660  public:
664  size_t num_simplices() {
665  return num_simplices(root());
666  }
667 
668  private:
670  size_t num_simplices(Siblings * sib) {
671  auto sib_begin = sib->members().begin();
672  auto sib_end = sib->members().end();
673  size_t simplices_number = sib->members().size();
674  for (auto sh = sib_begin; sh != sib_end; ++sh) {
675  if (has_children(sh)) {
676  simplices_number += num_simplices(sh->second.children());
677  }
678  }
679  return simplices_number;
680  }
681 
688  int dimension(Siblings* curr_sib) {
689  int dim = -1;
690  while (curr_sib != nullptr) {
691  ++dim;
692  curr_sib = curr_sib->oncles();
693  }
694  return dim;
695  }
696 
697  public:
699  std::vector<size_t> num_simplices_by_dimension() {
700  if (is_empty()) return {};
701  // std::min in case the upper bound got crazy
702  std::vector<size_t> res(std::min(upper_bound_dimension()+1, max_dimension()+1));
703  auto fun = [&res](Simplex_handle, int dim) -> void { ++res[dim]; };
704  for_each_simplex(fun);
705  if (dimension_to_be_lowered_) {
706  GUDHI_CHECK(res.front() != 0, std::logic_error("Bug in Gudhi: non-empty complex has no vertex"));
707  while (res.back() == 0) res.pop_back();
708  dimension_ = static_cast<int>(res.size()) - 1;
709  dimension_to_be_lowered_ = false;
710  } else {
711  GUDHI_CHECK(res.back() != 0,
712  std::logic_error("Bug in Gudhi: there is no simplex of dimension the dimension of the complex"));
713  }
714  return res;
715  }
716 
721  return dimension(self_siblings(sh));
722  }
723 
725  int upper_bound_dimension() const {
726  return dimension_;
727  }
728 
733  int dimension() {
734  if (dimension_to_be_lowered_)
735  lower_upper_bound_dimension();
736  return dimension_;
737  }
738 
741  template<class SimplexHandle>
742  bool has_children(SimplexHandle sh) const {
743  // Here we rely on the root using null_vertex(), which cannot match any real vertex.
744  return (sh->second.children()->parent() == sh->first);
745  }
746 
747  private:
749 
753  Siblings* children(Simplex_handle sh) const {
754  GUDHI_CHECK(has_children(sh), std::invalid_argument("Simplex_tree::children - argument has no child"));
755  return sh->second.children();
756  }
757 
758  public:
766  template<class InputVertexRange = std::initializer_list<Vertex_handle>>
767  Simplex_handle find(const InputVertexRange & s) {
768  auto first = std::begin(s);
769  auto last = std::end(s);
770 
771  if (first == last)
772  return null_simplex(); // ----->>
773 
774  // Copy before sorting
775  std::vector<Vertex_handle> copy(first, last);
776  std::sort(std::begin(copy), std::end(copy));
777  return find_simplex(copy);
778  }
779 
780  private:
782  Simplex_handle find_simplex(const std::vector<Vertex_handle> & simplex) {
783  Siblings * tmp_sib = &root_;
784  Dictionary_it tmp_dit;
785  auto vi = simplex.begin();
786  if constexpr (Options::contiguous_vertices && !Options::stable_simplex_handles) {
787  // Equivalent to the first iteration of the normal loop
788  GUDHI_CHECK(contiguous_vertices(), "non-contiguous vertices");
789  Vertex_handle v = *vi++;
790  if(v < 0 || v >= static_cast<Vertex_handle>(root_.members_.size()))
791  return null_simplex();
792  tmp_dit = root_.members_.begin() + v;
793  if (vi == simplex.end())
794  return tmp_dit;
795  if (!has_children(tmp_dit))
796  return null_simplex();
797  tmp_sib = tmp_dit->second.children();
798  }
799  for (;;) {
800  tmp_dit = tmp_sib->members_.find(*vi++);
801  if (tmp_dit == tmp_sib->members_.end())
802  return null_simplex();
803  if (vi == simplex.end())
804  return tmp_dit;
805  if (!has_children(tmp_dit))
806  return null_simplex();
807  tmp_sib = tmp_dit->second.children();
808  }
809  }
810 
813  Simplex_handle find_vertex(Vertex_handle v) {
814  if constexpr (Options::contiguous_vertices && !Options::stable_simplex_handles) {
815  assert(contiguous_vertices());
816  return root_.members_.begin() + v;
817  } else {
818  return root_.members_.find(v);
819  }
820  }
821 
822  public:
824  bool contiguous_vertices() const {
825  if (root_.members_.empty()) return true;
826  if (root_.members_.begin()->first != 0) return false;
827  if (std::prev(root_.members_.end())->first != static_cast<Vertex_handle>(root_.members_.size() - 1)) return false;
828  return true;
829  }
830 
831  protected:
846  template <class RandomVertexHandleRange = std::initializer_list<Vertex_handle>>
847  std::pair<Simplex_handle, bool> insert_simplex_raw(const RandomVertexHandleRange& simplex,
849  Siblings * curr_sib = &root_;
850  std::pair<Simplex_handle, bool> res_insert;
851  auto vi = simplex.begin();
852  for (; vi != std::prev(simplex.end()); ++vi) {
853  GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
854  res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
855  if (res_insert.second) {
856  // Only required when insertion is successful
857  update_simplex_tree_after_node_insertion(res_insert.first);
858  }
859  if (!(has_children(res_insert.first))) {
860  res_insert.first->second.assign_children(new Siblings(curr_sib, *vi));
861  }
862  curr_sib = res_insert.first->second.children();
863  }
864  GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
865  res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
866  if (!res_insert.second) {
867  // if already in the complex
868  if (res_insert.first->second.filtration() > filtration) {
869  // if filtration value modified
870  res_insert.first->second.assign_filtration(filtration);
871  return res_insert;
872  }
873  // if filtration value unchanged
874  return std::pair<Simplex_handle, bool>(null_simplex(), false);
875  } else {
876  // Only required when insertion is successful
877  update_simplex_tree_after_node_insertion(res_insert.first);
878  }
879  // otherwise the insertion has succeeded - size is a size_type
880  int dim = static_cast<int>(boost::size(simplex)) - 1;
881  if (dim > dimension_) {
882  // Update dimension if needed
883  dimension_ = dim;
884  }
885  return res_insert;
886  }
887 
888  public:
912  template<class InputVertexRange = std::initializer_list<Vertex_handle>>
913  std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex,
915  auto first = std::begin(simplex);
916  auto last = std::end(simplex);
917 
918  if (first == last)
919  return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->>
920 
921  // Copy before sorting
922  std::vector<Vertex_handle> copy(first, last);
923  std::sort(std::begin(copy), std::end(copy));
924  return insert_simplex_raw(copy, filtration);
925  }
926 
941  template<class InputVertexRange = std::initializer_list<Vertex_handle>>
942  std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex,
944  auto first = std::begin(Nsimplex);
945  auto last = std::end(Nsimplex);
946 
947  if (first == last)
948  return { null_simplex(), true }; // FIXME: false would make more sense to me.
949 
950  thread_local std::vector<Vertex_handle> copy;
951  copy.clear();
952  copy.insert(copy.end(), first, last);
953  std::sort(copy.begin(), copy.end());
954  auto last_unique = std::unique(copy.begin(), copy.end());
955  copy.erase(last_unique, copy.end());
956  GUDHI_CHECK_code(
957  for (Vertex_handle v : copy)
958  GUDHI_CHECK(v != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
959  )
960  // Update dimension if needed. We could wait to see if the insertion succeeds, but I doubt there is much to gain.
961  dimension_ = (std::max)(dimension_, static_cast<int>(std::distance(copy.begin(), copy.end())) - 1);
962 
963  return rec_insert_simplex_and_subfaces_sorted(root(), copy.begin(), copy.end(), filtration);
964  }
965 
966  private:
967  // To insert {1,2,3,4}, we insert {2,3,4} twice, once at the root, and once below 1.
968  template<class ForwardVertexIterator>
969  std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces_sorted(Siblings* sib,
970  ForwardVertexIterator first,
971  ForwardVertexIterator last,
972  Filtration_value filt) {
973  // An alternative strategy would be:
974  // - try to find the complete simplex, if found (and low filtration) exit
975  // - insert all the vertices at once in sib
976  // - loop over those (new or not) simplices, with a recursive call(++first, last)
977  Vertex_handle vertex_one = *first;
978  auto&& dict = sib->members();
979  auto insertion_result = dict.emplace(vertex_one, Node(sib, filt));
980  // update extra data structures in the insertion is successful
981  if (insertion_result.second) {
982  // Only required when insertion is successful
983  update_simplex_tree_after_node_insertion(insertion_result.first);
984  }
985 
986  Simplex_handle simplex_one = insertion_result.first;
987  bool one_is_new = insertion_result.second;
988  if (!one_is_new) {
989  if (filtration(simplex_one) > filt) {
990  assign_filtration(simplex_one, filt);
991  } else {
992  // FIXME: this interface makes no sense, and it doesn't seem to be tested.
993  insertion_result.first = null_simplex();
994  }
995  }
996  if (++first == last) return insertion_result;
997  if (!has_children(simplex_one))
998  // TODO: have special code here, we know we are building the whole subtree from scratch.
999  simplex_one->second.assign_children(new Siblings(sib, vertex_one));
1000  auto res = rec_insert_simplex_and_subfaces_sorted(simplex_one->second.children(), first, last, filt);
1001  // No need to continue if the full simplex was already there with a low enough filtration value.
1002  if (res.first != null_simplex()) rec_insert_simplex_and_subfaces_sorted(sib, first, last, filt);
1003  return res;
1004  }
1005 
1006  public:
1010  sh->second.assign_key(key);
1011  }
1012 
1016  std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) {
1017  assert(dimension(sh) == 1);
1018  return { find_vertex(sh->first), find_vertex(self_siblings(sh)->parent()) };
1019  }
1020 
1022  template<class SimplexHandle>
1023  static Siblings* self_siblings(SimplexHandle sh) {
1024  if (sh->second.children()->parent() == sh->first)
1025  return sh->second.children()->oncles();
1026  else
1027  return sh->second.children();
1028  }
1029 
1030  public:
1033  return &root_;
1034  }
1035 
1042  void set_dimension(int dimension, bool exact=true) {
1043  dimension_to_be_lowered_ = !exact;
1044  dimension_ = dimension;
1045  }
1046 
1047  public:
1055  void initialize_filtration(bool ignore_infinite_values = false) {
1056  filtration_vect_.clear();
1057  filtration_vect_.reserve(num_simplices());
1058  for (Simplex_handle sh : complex_simplex_range()) {
1059  if (ignore_infinite_values &&
1060  std::numeric_limits<Filtration_value>::has_infinity &&
1061  filtration(sh) == std::numeric_limits<Filtration_value>::infinity()) continue;
1062  filtration_vect_.push_back(sh);
1063  }
1064 
1065  /* We use stable_sort here because with libstdc++ it is faster than sort.
1066  * is_before_in_filtration is now a total order, but we used to call
1067  * stable_sort for the following heuristic:
1068  * The use of a depth-first traversal of the simplex tree, provided by
1069  * complex_simplex_range(), combined with a stable sort is meant to
1070  * optimize the order of simplices with same filtration value. The
1071  * heuristic consists in inserting the cofaces of a simplex as soon as
1072  * possible.
1073  */
1074 #ifdef GUDHI_USE_TBB
1075  tbb::parallel_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
1076 #else
1077  std::stable_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
1078 #endif
1079  }
1084  if (filtration_vect_.empty()) {
1086  }
1087  }
1093  filtration_vect_.clear();
1094  }
1095 
1096  private:
1109  void rec_coface(std::vector<Vertex_handle> &vertices, Siblings *curr_sib, int curr_nbVertices,
1110  std::vector<Simplex_handle>& cofaces, bool star, int nbVertices) {
1111  if (!(star || curr_nbVertices <= nbVertices)) // dimension of actual simplex <= nbVertices
1112  return;
1113  for (Simplex_handle simplex = curr_sib->members().begin(); simplex != curr_sib->members().end(); ++simplex) {
1114  if (vertices.empty()) {
1115  // If we reached the end of the vertices, and the simplex has more vertices than the given simplex
1116  // => we found a coface
1117 
1118  // Add a coface if we want the star or if the number of vertices of the current simplex matches with nbVertices
1119  bool addCoface = (star || curr_nbVertices == nbVertices);
1120  if (addCoface)
1121  cofaces.push_back(simplex);
1122  if ((!addCoface || star) && has_children(simplex)) // Rec call
1123  rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
1124  } else {
1125  if (simplex->first == vertices.back()) {
1126  // If curr_sib matches with the top vertex
1127  bool equalDim = (star || curr_nbVertices == nbVertices); // dimension of actual simplex == nbVertices
1128  bool addCoface = vertices.size() == 1 && equalDim;
1129  if (addCoface)
1130  cofaces.push_back(simplex);
1131  if ((!addCoface || star) && has_children(simplex)) {
1132  // Rec call
1133  Vertex_handle tmp = vertices.back();
1134  vertices.pop_back();
1135  rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
1136  vertices.push_back(tmp);
1137  }
1138  } else if (simplex->first > vertices.back()) {
1139  return;
1140  } else {
1141  // (simplex->first < vertices.back()
1142  if (has_children(simplex))
1143  rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
1144  }
1145  }
1146  }
1147  }
1148 
1149  public:
1159  return cofaces_simplex_range(simplex, 0);
1160  }
1161 
1173  // codimension must be positive or null integer
1174  assert(codimension >= 0);
1175 
1176  if constexpr (Options::link_nodes_by_label) {
1178  Static_vertex_vector simp(rg.begin(), rg.end());
1179  // must be sorted in decreasing order
1180  assert(std::is_sorted(simp.begin(), simp.end(), std::greater<Vertex_handle>()));
1181  auto range = Optimized_star_simplex_range(Optimized_star_simplex_iterator(this, std::move(simp)),
1183  // Lazy filtered range
1184  Fast_cofaces_predicate select(this, codimension, this->dimension(simplex));
1185  return boost::adaptors::filter(range, select);
1186  } else {
1187  Cofaces_simplex_range cofaces;
1189  std::vector<Vertex_handle> copy(rg.begin(), rg.end());
1190  if (codimension + static_cast<int>(copy.size()) > dimension_ + 1 ||
1191  (codimension == 0 && static_cast<int>(copy.size()) > dimension_)) // n+codimension greater than dimension_
1192  return cofaces;
1193  // must be sorted in decreasing order
1194  assert(std::is_sorted(copy.begin(), copy.end(), std::greater<Vertex_handle>()));
1195  bool star = codimension == 0;
1196  rec_coface(copy, &root_, 1, cofaces, star, codimension + static_cast<int>(copy.size()));
1197  return cofaces;
1198  }
1199  }
1200 
1201  private:
1209  bool reverse_lexicographic_order(Simplex_handle sh1, Simplex_handle sh2) {
1212  Simplex_vertex_iterator it1 = rg1.begin();
1213  Simplex_vertex_iterator it2 = rg2.begin();
1214  while (it1 != rg1.end() && it2 != rg2.end()) {
1215  if (*it1 == *it2) {
1216  ++it1;
1217  ++it2;
1218  } else {
1219  return *it1 < *it2;
1220  }
1221  }
1222  return ((it1 == rg1.end()) && (it2 != rg2.end()));
1223  }
1224 
1231  struct is_before_in_filtration {
1232  explicit is_before_in_filtration(Simplex_tree * st)
1233  : st_(st) { }
1234 
1235  bool operator()(const Simplex_handle sh1, const Simplex_handle sh2) const {
1236  // Not using st_->filtration(sh1) because it uselessly tests for null_simplex.
1237  if (sh1->second.filtration() != sh2->second.filtration()) {
1238  return sh1->second.filtration() < sh2->second.filtration();
1239  }
1240  // is sh1 a proper subface of sh2
1241  return st_->reverse_lexicographic_order(sh1, sh2);
1242  }
1243 
1244  Simplex_tree * st_;
1245  };
1246 
1247  public:
1271  template<class OneSkeletonGraph>
1272  void insert_graph(const OneSkeletonGraph& skel_graph) {
1273  // the simplex tree must be empty
1274  assert(num_simplices() == 0);
1275 
1276  // is there a better way to let the compiler know that we don't mean Simplex_tree::num_vertices?
1277  using boost::num_vertices;
1278 
1279  if (num_vertices(skel_graph) == 0) {
1280  return;
1281  }
1282  if (num_edges(skel_graph) == 0) {
1283  dimension_ = 0;
1284  } else {
1285  dimension_ = 1;
1286  }
1287 
1288  if constexpr (!Options::stable_simplex_handles)
1289  root_.members_.reserve(num_vertices(skel_graph)); // probably useless in most cases
1290  auto verts = vertices(skel_graph) | boost::adaptors::transformed([&](auto v){
1291  return Dit_value_t(v, Node(&root_, get(vertex_filtration_t(), skel_graph, v))); });
1292  root_.members_.insert(boost::begin(verts), boost::end(verts));
1293  // This automatically sorts the vertices, the graph concept doesn't guarantee the order in which we iterate.
1294 
1295  for (Dictionary_it it = boost::begin(root_.members_); it != boost::end(root_.members_); it++) {
1296  update_simplex_tree_after_node_insertion(it);
1297  }
1298 
1299  std::pair<typename boost::graph_traits<OneSkeletonGraph>::edge_iterator,
1300  typename boost::graph_traits<OneSkeletonGraph>::edge_iterator> boost_edges = edges(skel_graph);
1301  // boost_edges.first is the equivalent to boost_edges.begin()
1302  // boost_edges.second is the equivalent to boost_edges.end()
1303  for (; boost_edges.first != boost_edges.second; boost_edges.first++) {
1304  auto edge = *(boost_edges.first);
1305  auto u = source(edge, skel_graph);
1306  auto v = target(edge, skel_graph);
1307  if (u == v) throw std::invalid_argument("Self-loops are not simplicial");
1308  // We cannot skip edges with the wrong orientation and expect them to
1309  // come a second time with the right orientation, that does not always
1310  // happen in practice. emplace() should be a NOP when an element with the
1311  // same key is already there, so seeing the same edge multiple times is
1312  // ok.
1313  // Should we actually forbid multiple edges? That would be consistent
1314  // with rejecting self-loops.
1315  if (v < u) std::swap(u, v);
1316  auto sh = find_vertex(u);
1317  if (!has_children(sh)) {
1318  sh->second.assign_children(new Siblings(&root_, sh->first));
1319  }
1320 
1321  auto insertion_res = sh->second.children()->members().emplace(
1322  v, Node(sh->second.children(), get(edge_filtration_t(), skel_graph, edge)));
1323  if (insertion_res.second) update_simplex_tree_after_node_insertion(insertion_res.first);
1324  }
1325  }
1326 
1334  template <class VertexRange>
1335  void insert_batch_vertices(VertexRange const& vertices, Filtration_value filt = 0) {
1336  auto verts = vertices | boost::adaptors::transformed([&](auto v){
1337  return Dit_value_t(v, Node(&root_, filt)); });
1338  root_.members_.insert(boost::begin(verts), boost::end(verts));
1339  if (dimension_ < 0 && !root_.members_.empty()) dimension_ = 0;
1340  if constexpr (Options::link_nodes_by_label) {
1341  for (auto sh = root_.members().begin(); sh != root_.members().end(); sh++) {
1342  // update newly inserted simplex (the one that are not linked)
1343  if (!sh->second.list_max_vertex_hook_.is_linked())
1344  update_simplex_tree_after_node_insertion(sh);
1345  }
1346  }
1347  }
1348 
1360  void expansion(int max_dim) {
1361  if (max_dim <= 1) return;
1362  clear_filtration(); // Drop the cache.
1363  dimension_ = max_dim;
1364  for (Dictionary_it root_it = root_.members_.begin();
1365  root_it != root_.members_.end(); ++root_it) {
1366  if (has_children(root_it)) {
1367  siblings_expansion(root_it->second.children(), max_dim - 1);
1368  }
1369  }
1370  dimension_ = max_dim - dimension_;
1371  }
1372 
1408  , Vertex_handle v
1409  , Filtration_value fil
1410  , int dim_max
1411  , std::vector<Simplex_handle>& added_simplices)
1412  {
1432  static_assert(Options::link_nodes_by_label, "Options::link_nodes_by_label must be true");
1433 
1434  if (u == v) { // Are we inserting a vertex?
1435  auto res_ins = root_.members().emplace(u, Node(&root_,fil));
1436  if (res_ins.second) { //if the vertex is not in the complex, insert it
1437  added_simplices.push_back(res_ins.first); //no more insert in root_.members()
1438  update_simplex_tree_after_node_insertion(res_ins.first);
1439  if (dimension_ == -1) dimension_ = 0;
1440  }
1441  return; //because the vertex is isolated, no more insertions.
1442  }
1443  // else, we are inserting an edge: ensure that u < v
1444  if (v < u) { std::swap(u,v); }
1445 
1446  //Note that we copy Simplex_handle (aka map iterators) in added_simplices
1447  //while we are still modifying the Simplex_tree. Insertions in siblings may
1448  //invalidate Simplex_handles; we take care of this fact by first doing all
1449  //insertion in a Sibling, then inserting all handles in added_simplices.
1450 
1451 #ifdef GUDHI_DEBUG
1452  //check whether vertices u and v are in the tree. If not, return an error.
1453  auto sh_u = root_.members().find(u);
1454  GUDHI_CHECK(sh_u != root_.members().end() &&
1455  root_.members().find(v) != root_.members().end(),
1456  std::invalid_argument(
1457  "Simplex_tree::insert_edge_as_flag - inserts an edge whose vertices are not in the complex")
1458  );
1459  GUDHI_CHECK(!has_children(sh_u) ||
1460  sh_u->second.children()->members().find(v) == sh_u->second.children()->members().end(),
1461  std::invalid_argument(
1462  "Simplex_tree::insert_edge_as_flag - inserts an already existing edge")
1463  );
1464 #endif
1465 
1466  // to update dimension
1467  const auto tmp_dim = dimension_;
1468  auto tmp_max_dim = dimension_;
1469 
1470  //for all siblings containing a Node labeled with u (including the root), run
1471  //compute_punctual_expansion
1472  //todo parallelise
1473  List_max_vertex* nodes_with_label_u = nodes_by_label(u);//all Nodes with u label
1474 
1475  GUDHI_CHECK(nodes_with_label_u != nullptr,
1476  "Simplex_tree::insert_edge_as_flag - cannot find the list of Nodes with label u");
1477 
1478  for (auto&& node_as_hook : *nodes_with_label_u)
1479  {
1480  Node& node_u = static_cast<Node&>(node_as_hook); //corresponding node, has label u
1481  Simplex_handle sh_u = simplex_handle_from_node(node_u);
1482  Siblings * sib_u = self_siblings(sh_u);
1483  if (sib_u->members().find(v) != sib_u->members().end()) { //v is the label of a sibling of node_u
1484  int curr_dim = dimension(sib_u);
1485  if (dim_max == -1 || curr_dim < dim_max){
1486  if (!has_children(sh_u)) {
1487  //then node_u was a leaf and now has a new child Node labeled v
1488  //the child v is created in compute_punctual_expansion
1489  node_u.assign_children(new Siblings(sib_u, u));
1490  }
1491  dimension_ = dim_max - curr_dim - 1;
1492  compute_punctual_expansion(
1493  v,
1494  node_u.children(),
1495  fil,
1496  dim_max - curr_dim - 1, //>= 0 if dim_max >= 0, <0 otherwise
1497  added_simplices );
1498  dimension_ = dim_max - dimension_;
1499  if (dimension_ > tmp_max_dim) tmp_max_dim = dimension_;
1500  }
1501  }
1502  }
1503  if (tmp_dim <= tmp_max_dim){
1504  dimension_ = tmp_max_dim;
1505  dimension_to_be_lowered_ = false;
1506  } else {
1507  dimension_ = tmp_dim;
1508  }
1509  }
1510 
1511  private:
1521  void compute_punctual_expansion( Vertex_handle v
1522  , Siblings * sib
1523  , Filtration_value fil
1524  , int k //k == dim_max - dimension simplices in sib
1525  , std::vector<Simplex_handle>& added_simplices )
1526  { //insertion always succeeds because the edge {u,v} used to not be here.
1527  auto res_ins_v = sib->members().emplace(v, Node(sib,fil));
1528  added_simplices.push_back(res_ins_v.first); //no more insertion in sib
1529  update_simplex_tree_after_node_insertion(res_ins_v.first);
1530 
1531  if (k == 0) { // reached the maximal dimension. if max_dim == -1, k is never equal to 0.
1532  dimension_ = 0; // to keep track of the max height of the recursion tree
1533  return;
1534  }
1535 
1536  //create the subtree of new Node(v)
1537  create_local_expansion( res_ins_v.first
1538  , sib
1539  , fil
1540  , k
1541  , added_simplices );
1542 
1543  //punctual expansion in nodes on the left of v, i.e. with label x < v
1544  for (auto sh = sib->members().begin(); sh != res_ins_v.first; ++sh)
1545  { //if v belongs to N^+(x), punctual expansion
1546  Simplex_handle root_sh = find_vertex(sh->first); //Node(x), x < v
1547  if (has_children(root_sh) &&
1548  root_sh->second.children()->members().find(v) != root_sh->second.children()->members().end())
1549  { //edge {x,v} is in the complex
1550  if (!has_children(sh)){
1551  sh->second.assign_children(new Siblings(sib, sh->first));
1552  }
1553  //insert v in the children of sh, and expand.
1554  compute_punctual_expansion( v
1555  , sh->second.children()
1556  , fil
1557  , k-1
1558  , added_simplices );
1559  }
1560  }
1561  }
1562 
1569  void create_local_expansion(
1570  Simplex_handle sh_v //Node with label v which has just been inserted
1571  , Siblings * curr_sib //Siblings containing the node sh_v
1572  , Filtration_value fil_uv //Fil value of the edge uv in the zz filtration
1573  , int k //Stopping condition for recursion based on max dim
1574  , std::vector<Simplex_handle> &added_simplices) //range of all new simplices
1575  { //pick N^+(v)
1576  //intersect N^+(v) with labels y > v in curr_sib
1577  Simplex_handle next_it = sh_v;
1578  ++next_it;
1579 
1580  if (dimension_ > k) {
1581  dimension_ = k; //to keep track of the max height of the recursion tree
1582  }
1583 
1584  create_expansion<true>(curr_sib, sh_v, next_it, fil_uv, k, &added_simplices);
1585  }
1586  //TODO boost::container::ordered_unique_range_t in the creation of a Siblings
1587 
1596  void siblings_expansion(
1597  Siblings * siblings // must contain elements
1598  , Filtration_value fil
1599  , int k // == max_dim expansion - dimension curr siblings
1600  , std::vector<Simplex_handle> & added_simplices )
1601  {
1602  if (dimension_ > k) {
1603  dimension_ = k; //to keep track of the max height of the recursion tree
1604  }
1605  if (k == 0) { return; } //max dimension
1606  Dictionary_it next = ++(siblings->members().begin());
1607 
1608  for (Dictionary_it s_h = siblings->members().begin();
1609  next != siblings->members().end(); ++s_h, ++next)
1610  { //find N^+(s_h)
1611  create_expansion<true>(siblings, s_h, next, fil, k, &added_simplices);
1612  }
1613  }
1614 
1617  void siblings_expansion(Siblings * siblings, // must contain elements
1618  int k) {
1619  if (k >= 0 && dimension_ > k) {
1620  dimension_ = k;
1621  }
1622  if (k == 0)
1623  return;
1624  Dictionary_it next = siblings->members().begin();
1625  ++next;
1626 
1627  for (Dictionary_it s_h = siblings->members().begin();
1628  s_h != siblings->members().end(); ++s_h, ++next)
1629  {
1630  create_expansion<false>(siblings, s_h, next, s_h->second.filtration(), k);
1631  }
1632  }
1633 
1638  template<bool force_filtration_value>
1639  void create_expansion(Siblings * siblings,
1640  Dictionary_it& s_h,
1641  Dictionary_it& next,
1642  Filtration_value fil,
1643  int k,
1644  std::vector<Simplex_handle>* added_simplices = nullptr)
1645  {
1646  Simplex_handle root_sh = find_vertex(s_h->first);
1647  thread_local std::vector<std::pair<Vertex_handle, Node> > inter;
1648 
1649  if (!has_children(root_sh)) return;
1650 
1651  intersection<force_filtration_value>(
1652  inter, // output intersection
1653  next, // begin
1654  siblings->members().end(), // end
1655  root_sh->second.children()->members().begin(),
1656  root_sh->second.children()->members().end(),
1657  fil);
1658  if (inter.size() != 0) {
1659  Siblings * new_sib = new Siblings(siblings, // oncles
1660  s_h->first, // parent
1661  inter); // boost::container::ordered_unique_range_t
1662  for (auto it = new_sib->members().begin(); it != new_sib->members().end(); ++it) {
1663  update_simplex_tree_after_node_insertion(it);
1664  if constexpr (force_filtration_value){
1665  //the way create_expansion is used, added_simplices != nullptr when force_filtration_value == true
1666  added_simplices->push_back(it);
1667  }
1668  }
1669  inter.clear();
1670  s_h->second.assign_children(new_sib);
1671  if constexpr (force_filtration_value){
1672  siblings_expansion(new_sib, fil, k - 1, *added_simplices);
1673  } else {
1674  siblings_expansion(new_sib, k - 1);
1675  }
1676  } else {
1677  // ensure the children property
1678  s_h->second.assign_children(siblings);
1679  inter.clear();
1680  }
1681  }
1682 
1685  template<bool force_filtration_value = false>
1686  static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection,
1687  Dictionary_it begin1, Dictionary_it end1,
1688  Dictionary_it begin2, Dictionary_it end2,
1689  Filtration_value filtration_) {
1690  if (begin1 == end1 || begin2 == end2)
1691  return; // ----->>
1692  while (true) {
1693  if (begin1->first == begin2->first) {
1694  if constexpr (force_filtration_value){
1695  intersection.emplace_back(begin1->first, Node(nullptr, filtration_));
1696  } else {
1697  Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_});
1698  intersection.emplace_back(begin1->first, Node(nullptr, filt));
1699  }
1700  if (++begin1 == end1 || ++begin2 == end2)
1701  return; // ----->>
1702  } else if (begin1->first < begin2->first) {
1703  if (++begin1 == end1)
1704  return;
1705  } else /* begin1->first > begin2->first */ {
1706  if (++begin2 == end2)
1707  return; // ----->>
1708  }
1709  }
1710  }
1711 
1712  public:
1731  template< typename Blocker >
1732  void expansion_with_blockers(int max_dim, Blocker block_simplex) {
1733  // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1734  for (auto& simplex : boost::adaptors::reverse(root_.members())) {
1735  if (has_children(&simplex)) {
1736  siblings_expansion_with_blockers(simplex.second.children(), max_dim, max_dim - 1, block_simplex);
1737  }
1738  }
1739  }
1740 
1741  private:
1743  template< typename Blocker >
1744  void siblings_expansion_with_blockers(Siblings* siblings, int max_dim, int k, Blocker block_simplex) {
1745  if (dimension_ < max_dim - k) {
1746  dimension_ = max_dim - k;
1747  }
1748  if (k == 0)
1749  return;
1750  // No need to go deeper
1751  if (siblings->members().size() < 2)
1752  return;
1753  // Reverse loop starting before the last one for 'next' to be the last one
1754  for (auto simplex = std::next(siblings->members().rbegin()); simplex != siblings->members().rend(); simplex++) {
1755  std::vector<std::pair<Vertex_handle, Node> > intersection;
1756  for(auto next = siblings->members().rbegin(); next != simplex; next++) {
1757  bool to_be_inserted = true;
1758  Filtration_value filt = simplex->second.filtration();
1759  // If all the boundaries are present, 'next' needs to be inserted
1760  for (Simplex_handle border : boundary_simplex_range(simplex)) {
1761  Simplex_handle border_child = find_child(border, next->first);
1762  if (border_child == null_simplex()) {
1763  to_be_inserted=false;
1764  break;
1765  }
1766  filt = (std::max)(filt, filtration(border_child));
1767  }
1768  if (to_be_inserted) {
1769  intersection.emplace_back(next->first, Node(nullptr, filt));
1770  }
1771  }
1772  if (intersection.size() != 0) {
1773  // Reverse the order to insert
1774  Siblings * new_sib = new Siblings(
1775  siblings, // oncles
1776  simplex->first, // parent
1777  boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t
1778  simplex->second.assign_children(new_sib);
1779  std::vector<Vertex_handle> blocked_new_sib_vertex_list;
1780  // As all intersections are inserted, we can call the blocker function on all new_sib members
1781  for (auto new_sib_member = new_sib->members().begin();
1782  new_sib_member != new_sib->members().end();
1783  new_sib_member++) {
1784  update_simplex_tree_after_node_insertion(new_sib_member);
1785  bool blocker_result = block_simplex(new_sib_member);
1786  // new_sib member has been blocked by the blocker function
1787  // add it to the list to be removed - do not perform it while looping on it
1788  if (blocker_result) {
1789  blocked_new_sib_vertex_list.push_back(new_sib_member->first);
1790  // update data structures for all deleted simplices
1791  // can be done in the loop as part of another datastructure
1792  update_simplex_tree_before_node_removal(new_sib_member);
1793  }
1794  }
1795  if (blocked_new_sib_vertex_list.size() == new_sib->members().size()) {
1796  // Specific case where all have to be deleted
1797  delete new_sib;
1798  // ensure the children property
1799  simplex->second.assign_children(siblings);
1800  } else {
1801  for (auto& blocked_new_sib_member : blocked_new_sib_vertex_list) {
1802  new_sib->members().erase(blocked_new_sib_member);
1803  }
1804  // ensure recursive call
1805  siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex);
1806  }
1807  } else {
1808  // ensure the children property
1809  simplex->second.assign_children(siblings);
1810  }
1811  }
1812  }
1813 
1818  Simplex_handle find_child(Simplex_handle sh, Vertex_handle vh) const {
1819  if (!has_children(sh))
1820  return null_simplex();
1821 
1822  Simplex_handle child = sh->second.children()->find(vh);
1823  // Specific case of boost::flat_map does not find, returns boost::flat_map::end()
1824  // in simplex tree we want a null_simplex()
1825  if (child == sh->second.children()->members().end())
1826  return null_simplex();
1827 
1828  return child;
1829  }
1830 
1831  public:
1838  void print_hasse(std::ostream& os) {
1839  os << num_simplices() << " " << std::endl;
1840  for (auto sh : filtration_simplex_range()) {
1841  os << dimension(sh) << " ";
1842  for (auto b_sh : boundary_simplex_range(sh)) {
1843  os << key(b_sh) << " ";
1844  }
1845  os << filtration(sh) << " \n";
1846  }
1847  }
1848 
1849  public:
1858  template<class Fun>
1859  void for_each_simplex(Fun&& fun) {
1860  // Wrap callback so it always returns bool
1861  auto f = [&fun](Simplex_handle sh, int dim) -> bool {
1862  if constexpr (std::is_same_v<void, decltype(fun(sh, dim))>) {
1863  fun(sh, dim);
1864  return false;
1865  } else {
1866  return fun(sh, dim);
1867  }
1868  };
1869  if (!is_empty())
1870  rec_for_each_simplex(root(), 0, f);
1871  }
1872 
1873  private:
1874  template<class Fun>
1875  void rec_for_each_simplex(Siblings* sib, int dim, Fun&& fun) {
1876  Simplex_handle sh = sib->members().end();
1877  GUDHI_CHECK(sh != sib->members().begin(), "Bug in Gudhi: only the root siblings may be empty");
1878  do {
1879  --sh;
1880  if (!fun(sh, dim) && has_children(sh)) {
1881  rec_for_each_simplex(sh->second.children(), dim+1, fun);
1882  }
1883  // We could skip checking has_children for the first element of the iteration, we know it returns false.
1884  }
1885  while(sh != sib->members().begin());
1886  }
1887 
1888  public:
1896  bool modified = false;
1897  auto fun = [&modified, this](Simplex_handle sh, int dim) -> void {
1898  if (dim == 0) return;
1899  // Find the maximum filtration value in the border
1901  Boundary_simplex_iterator max_border = std::max_element(std::begin(boundary), std::end(boundary),
1902  [](Simplex_handle sh1, Simplex_handle sh2) {
1903  return filtration(sh1) < filtration(sh2);
1904  });
1905 
1906  Filtration_value max_filt_border_value = filtration(*max_border);
1907  // Replacing if(f<max) with if(!(f>=max)) would mean that if f is NaN, we replace it with the max of the children.
1908  // That seems more useful than keeping NaN.
1909  if (!(sh->second.filtration() >= max_filt_border_value)) {
1910  // Store the filtration modification information
1911  modified = true;
1912  sh->second.assign_filtration(max_filt_border_value);
1913  }
1914  };
1915  // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1916  for_each_simplex(fun);
1917 
1918  if(modified)
1919  clear_filtration(); // Drop the cache.
1920  return modified;
1921  }
1922 
1923  public:
1925  void clear() {
1926  root_members_recursive_deletion();
1927  clear_filtration();
1928  dimension_ = -1;
1929  dimension_to_be_lowered_ = false;
1930  if constexpr (Options::link_nodes_by_label)
1931  nodes_label_to_list_.clear();
1932  }
1933 
1942  if (std::numeric_limits<Filtration_value>::has_infinity && filtration == std::numeric_limits<Filtration_value>::infinity())
1943  return false; // ---->>
1944  bool modified = rec_prune_above_filtration(root(), filtration);
1945  if(modified)
1946  clear_filtration(); // Drop the cache.
1947  return modified;
1948  }
1949 
1950  private:
1951  bool rec_prune_above_filtration(Siblings* sib, Filtration_value filt) {
1952  auto&& list = sib->members();
1953  bool modified = false;
1954  bool emptied = false;
1955  Simplex_handle last;
1956 
1957  auto to_remove = [this, filt](Dit_value_t& simplex) {
1958  if (simplex.second.filtration() <= filt) return false;
1959  if (has_children(&simplex)) rec_delete(simplex.second.children());
1960  // dimension may need to be lowered
1961  dimension_to_be_lowered_ = true;
1962  return true;
1963  };
1964 
1965  //TODO: `if constexpr` replacable by `std::erase_if` in C++20? Has a risk of additional runtime,
1966  //so to benchmark first.
1967  if constexpr (Options::stable_simplex_handles) {
1968  modified = false;
1969  for (auto sh = list.begin(); sh != list.end();) {
1970  if (to_remove(*sh)) {
1971  sh = list.erase(sh);
1972  modified = true;
1973  } else {
1974  ++sh;
1975  }
1976  }
1977  emptied = (list.empty() && sib != root());
1978  } else {
1979  last = std::remove_if(list.begin(), list.end(), to_remove);
1980  modified = (last != list.end());
1981  emptied = (last == list.begin() && sib != root());
1982  }
1983 
1984  if (emptied) {
1985  // Removing the whole siblings, parent becomes a leaf.
1986  sib->oncles()->members()[sib->parent()].assign_children(sib->oncles());
1987  delete sib;
1988  // dimension may need to be lowered
1989  dimension_to_be_lowered_ = true;
1990  return true;
1991  } else {
1992  // Keeping some elements of siblings. Remove the others, and recurse in the remaining ones.
1993  if constexpr (!Options::stable_simplex_handles) list.erase(last, list.end());
1994  for (auto&& simplex : list)
1995  if (has_children(&simplex)) modified |= rec_prune_above_filtration(simplex.second.children(), filt);
1996  }
1997 
1998  return modified;
1999  }
2000 
2001  public:
2007  if (dimension >= dimension_)
2008  return false;
2009 
2010  bool modified = false;
2011  if (dimension < 0) {
2012  if (num_vertices() > 0) {
2013  root_members_recursive_deletion();
2014  modified = true;
2015  }
2016  // Force dimension to -1, in case user calls `prune_above_dimension(-10)`
2017  dimension = -1;
2018  } else {
2019  modified = rec_prune_above_dimension(root(), dimension, 0);
2020  }
2021  if(modified) {
2022  // Thanks to `if (dimension >= dimension_)` and dimension forced to -1 `if (dimension < 0)`, we know the new dimension
2023  dimension_ = dimension;
2024  clear_filtration(); // Drop the cache.
2025  }
2026  return modified;
2027  }
2028 
2029  private:
2030  bool rec_prune_above_dimension(Siblings* sib, int dim, int actual_dim) {
2031  bool modified = false;
2032  auto&& list = sib->members();
2033 
2034  for (auto&& simplex : list)
2035  if (has_children(&simplex)) {
2036  if (actual_dim >= dim) {
2037  rec_delete(simplex.second.children());
2038  simplex.second.assign_children(sib);
2039  modified = true;
2040  } else {
2041  modified |= rec_prune_above_dimension(simplex.second.children(), dim, actual_dim + 1);
2042  }
2043  }
2044 
2045  return modified;
2046  }
2047 
2048  private:
2054  bool lower_upper_bound_dimension() {
2055  // reset automatic detection to recompute
2056  dimension_to_be_lowered_ = false;
2057  int new_dimension = -1;
2058  // Browse the tree from the left to the right as higher dimension cells are more likely on the left part of the tree
2059  for (Simplex_handle sh : complex_simplex_range()) {
2060 #ifdef DEBUG_TRACES
2061  for (auto vertex : simplex_vertex_range(sh)) {
2062  std::clog << " " << vertex;
2063  }
2064  std::clog << std::endl;
2065 #endif // DEBUG_TRACES
2066 
2067  int sh_dimension = dimension(sh);
2068  if (sh_dimension >= dimension_)
2069  // Stop browsing as soon as the dimension is reached, no need to go further
2070  return false;
2071  new_dimension = (std::max)(new_dimension, sh_dimension);
2072  }
2073  dimension_ = new_dimension;
2074  return true;
2075  }
2076 
2077 
2078  public:
2088  // Guarantee the simplex has no children
2089  GUDHI_CHECK(!has_children(sh),
2090  std::invalid_argument("Simplex_tree::remove_maximal_simplex - argument has children"));
2091 
2092  update_simplex_tree_before_node_removal(sh);
2093 
2094  // Simplex is a leaf, it means the child is the Siblings owning the leaf
2095  Siblings* child = sh->second.children();
2096 
2097  if ((child->size() > 1) || (child == root())) {
2098  // Not alone, just remove it from members
2099  // Special case when child is the root of the simplex tree, just remove it from members
2100  child->erase(sh);
2101  } else {
2102  // Sibling is emptied : must be deleted, and its parent must point on his own Sibling
2103  child->oncles()->members().at(child->parent()).assign_children(child->oncles());
2104  delete child;
2105  // dimension may need to be lowered
2106  dimension_to_be_lowered_ = true;
2107  }
2108  }
2109 
2126  std::pair<Filtration_value, Extended_simplex_type> decode_extended_filtration(Filtration_value f, const Extended_filtration_data& efd){
2127  std::pair<Filtration_value, Extended_simplex_type> p;
2128  Filtration_value minval = efd.minval;
2129  Filtration_value maxval = efd.maxval;
2130  if (f >= -2 && f <= -1) {
2131  p.first = minval + (maxval-minval)*(f + 2); p.second = Extended_simplex_type::UP;
2132  } else if (f >= 1 && f <= 2) {
2133  p.first = minval - (maxval-minval)*(f - 2); p.second = Extended_simplex_type::DOWN;
2134  } else {
2135  p.first = std::numeric_limits<Filtration_value>::quiet_NaN(); p.second = Extended_simplex_type::EXTRA;
2136  }
2137  return p;
2138  };
2139 
2153  Extended_filtration_data extend_filtration() {
2154  clear_filtration(); // Drop the cache.
2155 
2156  // Compute maximum and minimum of filtration values
2157  Vertex_handle maxvert = std::numeric_limits<Vertex_handle>::min();
2158  Filtration_value minval = std::numeric_limits<Filtration_value>::infinity();
2159  Filtration_value maxval = -std::numeric_limits<Filtration_value>::infinity();
2160  for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh) {
2161  Filtration_value f = this->filtration(sh);
2162  minval = std::min(minval, f);
2163  maxval = std::max(maxval, f);
2164  maxvert = std::max(sh->first, maxvert);
2165  }
2166 
2167  GUDHI_CHECK(maxvert < std::numeric_limits<Vertex_handle>::max(), std::invalid_argument("Simplex_tree contains a vertex with the largest Vertex_handle"));
2168  maxvert++;
2169 
2170  Simplex_tree st_copy = *this;
2171 
2172  // Add point for coning the simplicial complex
2173  this->insert_simplex_raw({maxvert}, -3);
2174 
2175  Filtration_value scale = maxval-minval;
2176  if (scale != 0)
2177  scale = 1 / scale;
2178 
2179  // For each simplex
2180  std::vector<Vertex_handle> vr;
2181  for (auto sh_copy : st_copy.complex_simplex_range()) {
2182  auto&& simplex_range = st_copy.simplex_vertex_range(sh_copy);
2183  vr.assign(simplex_range.begin(), simplex_range.end());
2184  auto sh = this->find(vr);
2185 
2186  // Create cone on simplex
2187  vr.push_back(maxvert);
2188  if (this->dimension(sh) == 0) {
2189  Filtration_value v = this->filtration(sh);
2190  Filtration_value scaled_v = (v - minval) * scale;
2191  // Assign ascending value between -2 and -1 to vertex
2192  this->assign_filtration(sh, -2 + scaled_v);
2193  // Assign descending value between 1 and 2 to cone on vertex
2194  this->insert_simplex(vr, 2 - scaled_v);
2195  } else {
2196  // Assign value -3 to simplex and cone on simplex
2197  this->assign_filtration(sh, -3);
2198  this->insert_simplex(vr, -3);
2199  }
2200  }
2201 
2202  // Automatically assign good values for simplices
2204 
2205  // Return the filtration data
2206  return Extended_filtration_data(minval, maxval);
2207  }
2208 
2214  auto filt = filtration_(sh);
2215  for(auto v : simplex_vertex_range(sh))
2216  if(filtration_(find_vertex(v)) == filt)
2217  return v;
2218  return null_vertex();
2219  }
2220 
2228  // See issue #251 for potential speed improvements.
2229  auto&& vertices = simplex_vertex_range(sh); // vertices in decreasing order
2230  auto end = std::end(vertices);
2231  auto vi = std::begin(vertices);
2232  GUDHI_CHECK(vi != end, "empty simplex");
2233  auto v0 = *vi;
2234  ++vi;
2235  GUDHI_CHECK(vi != end, "simplex of dimension 0");
2236  if(std::next(vi) == end) return sh; // shortcut for dimension 1
2237  Static_vertex_vector suffix;
2238  suffix.push_back(v0);
2239  auto filt = filtration_(sh);
2240  do
2241  {
2242  Vertex_handle v = *vi;
2243  auto&& children1 = find_vertex(v)->second.children()->members_;
2244  for(auto w : suffix){
2245  // Can we take advantage of the fact that suffix is ordered?
2246  Simplex_handle s = children1.find(w);
2247  if(filtration_(s) == filt)
2248  return s;
2249  }
2250  suffix.push_back(v);
2251  }
2252  while(++vi != end);
2253  return null_simplex();
2254  }
2255 
2261  auto filt = filtration_(sh);
2262  // Naive implementation, it can be sped up.
2263  for(auto b : boundary_simplex_range(sh))
2264  if(filtration_(b) == filt)
2266  return sh; // None of its faces has the same filtration.
2267  }
2268 
2269  public:
2270  // intrusive list of Nodes with same label using the hooks
2271  typedef boost::intrusive::member_hook<Hooks_simplex_base_link_nodes, typename Hooks_simplex_base_link_nodes::Member_hook_t,
2272  &Hooks_simplex_base_link_nodes::list_max_vertex_hook_>
2273  List_member_hook_t;
2274  // auto_unlink in Member_hook_t is incompatible with constant time size
2275  typedef boost::intrusive::list<Hooks_simplex_base_link_nodes, List_member_hook_t,
2276  boost::intrusive::constant_time_size<false>> List_max_vertex;
2277  // type of hooks stored in each Node, Node inherits from Hooks_simplex_base
2278  typedef typename std::conditional<Options::link_nodes_by_label, Hooks_simplex_base_link_nodes,
2279  Hooks_simplex_base_dummy>::type Hooks_simplex_base;
2280 
2283  private:
2284  // if Options::link_nodes_by_label is true, store the lists of Nodes with same label, empty otherwise.
2285  // unordered_map Vertex_handle v -> list of all Nodes with label v.
2286  std::unordered_map<Vertex_handle, List_max_vertex> nodes_label_to_list_;
2287 
2288  List_max_vertex* nodes_by_label(Vertex_handle v) {
2289  if constexpr (Options::link_nodes_by_label) {
2290  auto it_v = nodes_label_to_list_.find(v);
2291  if (it_v != nodes_label_to_list_.end()) {
2292  return &(it_v->second);
2293  } else {
2294  return nullptr;
2295  }
2296  }
2297  return nullptr;
2298  }
2299 
2302  static Simplex_handle simplex_handle_from_node(Node& node) {
2303  if constexpr (Options::stable_simplex_handles){
2304  //Relies on the Dictionary type to be boost::container::map<Vertex_handle, Node>.
2305  //If the type changes or boost fondamentally changes something on the structure of their map,
2306  //a safer/more general but much slower version is:
2307  // if (node.children()->parent() == label) { // verifies if node is a leaf
2308  // return children->oncles()->find(label);
2309  // } else {
2310  // return children->members().find(label);
2311  // }
2312  //Requires an additional parameter "Vertex_handle label" which is the label of the node.
2313 
2314  Dictionary_it testIt = node.children()->members().begin();
2315  Node* testNode = &testIt->second;
2316  auto testIIt = testIt.get();
2317  auto testPtr = testIIt.pointed_node();
2318  //distance between node and pointer to map pair in memory
2319  auto shift = (const char*)(testNode) - (const char*)(testPtr);
2320 
2321  //decltype(testPtr) = boost::intrusive::compact_rbtree_node<void*>*
2322  decltype(testPtr) sh_ptr = decltype(testPtr)((const char*)(&node) - shift); //shifts from node to pointer
2323  //decltype(testIIt) =
2324  //boost::intrusive::tree_iterator<
2325  // boost::intrusive::bhtraits<
2326  // boost::container::base_node<
2327  // std::pair<const int, Simplex_tree_node_explicit_storage<Simplex_tree>>,
2328  // boost::container::dtl::intrusive_tree_hook<void*, boost::container::red_black_tree, true>, true>,
2329  // boost::intrusive::rbtree_node_traits<void*, true>,
2330  // boost::intrusive::normal_link,
2331  // boost::intrusive::dft_tag,
2332  // 3>,
2333  // false>
2334  decltype(testIIt) sh_ii;
2335  sh_ii = sh_ptr; //creates ``subiterator'' from pointer
2336  Dictionary_it sh(sh_ii); //creates iterator from subiterator
2337 
2338  return sh;
2339  } else {
2340  return (Simplex_handle)(boost::intrusive::get_parent_from_member<Dit_value_t>(&node, &Dit_value_t::second));
2341  }
2342  }
2343 
2344  // Give access to Simplex_tree_optimized_cofaces_rooted_subtrees_simplex_iterator and keep nodes_by_label and
2345  // simplex_handle_from_node private
2346  friend class Simplex_tree_optimized_cofaces_rooted_subtrees_simplex_iterator<Simplex_tree>;
2347 
2348  private:
2349  // update all extra data structures in the Simplex_tree. Must be called after all
2350  // simplex insertions.
2351  void update_simplex_tree_after_node_insertion(Simplex_handle sh) {
2352 #ifdef DEBUG_TRACES
2353  std::clog << "update_simplex_tree_after_node_insertion" << std::endl;
2354 #endif // DEBUG_TRACES
2355  if constexpr (Options::link_nodes_by_label) {
2356  // Creates an entry with sh->first if not already in the map and insert sh->second at the end of the list
2357  nodes_label_to_list_[sh->first].push_back(sh->second);
2358  }
2359  }
2360 
2361  // update all extra data structures in the Simplex_tree. Must be called before
2362  // all simplex removals
2363  void update_simplex_tree_before_node_removal(Simplex_handle sh) {
2364 #ifdef DEBUG_TRACES
2365  std::clog << "update_simplex_tree_before_node_removal" << std::endl;
2366 #endif // DEBUG_TRACES
2367  if constexpr (Options::link_nodes_by_label) {
2368  sh->second.unlink_hooks(); // remove from lists of same label Nodes
2369  if (nodes_label_to_list_[sh->first].empty())
2370  nodes_label_to_list_.erase(sh->first);
2371  }
2372  }
2373 
2374  public:
2383  void reset_filtration(Filtration_value filt_value, int min_dim = 0) {
2384  rec_reset_filtration(&root_, filt_value, min_dim);
2385  clear_filtration(); // Drop the cache.
2386  }
2387 
2388  private:
2394  void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int min_depth) {
2395  for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
2396  if (min_depth <= 0) {
2397  sh->second.assign_filtration(filt_value);
2398  }
2399  if (has_children(sh)) {
2400  rec_reset_filtration(sh->second.children(), filt_value, min_depth - 1);
2401  }
2402  }
2403  }
2404 
2405  public:
2413  std::size_t get_serialization_size() {
2414  const std::size_t vh_byte_size = sizeof(Vertex_handle);
2415  const std::size_t fv_byte_size = SimplexTreeOptions::store_filtration ? sizeof(Filtration_value) : 0;
2416  const std::size_t buffer_byte_size = vh_byte_size + num_simplices() * (fv_byte_size + 2 * vh_byte_size);
2417 #ifdef DEBUG_TRACES
2418  std::clog << "Gudhi::simplex_tree::get_serialization_size - buffer size = " << buffer_byte_size << std::endl;
2419 #endif // DEBUG_TRACES
2420  return buffer_byte_size;
2421  }
2422 
2433  /* Let's take the following simplicial complex as example: */
2434  /* (vertices are represented as letters to ease the understanding) */
2435  /* o---o---o */
2436  /* a b\X/c */
2437  /* o */
2438  /* d */
2439  /* The simplex tree is: */
2440  /* a o b o c o d o */
2441  /* | |\ | */
2442  /* b o c o o d o d */
2443  /* | */
2444  /* d o */
2445  /* The serialization is (without filtration values that comes right after vertex handle value): */
2446  /* 04(number of vertices)0a 0b 0c 0d(list of vertices)01(number of [a] children)0b([a,b] simplex) */
2447  /* 00(number of [a,b] children)02(number of [b] children)0c 0d(list of [b] children)01(number of [b,c] children) */
2448  /* 0d(list of [b,c] children)00(number of [b,c,d] children)00(number of [b,d] children)01(number of [c] children) */
2449  /* 0d(list of [c] children)00(number of [b,d] children)00(number of [d] children) */
2450  /* Without explanation and with filtration values: */
2451  /* 04 0a F(a) 0b F(b) 0c F(c) 0d F(d) 01 0b F(a,b) 00 02 0c F(b,c) 0d F(b,d) 01 0d F(b,c,d) 00 00 01 0d F(c,d) 00 00 */
2452  void serialize(char* buffer, const std::size_t buffer_size) {
2453  char* buffer_end = rec_serialize(&root_, buffer);
2454  if (static_cast<std::size_t>(buffer_end - buffer) != buffer_size)
2455  throw std::invalid_argument("Serialization does not match end of buffer");
2456  }
2457 
2458  private:
2460  char* rec_serialize(Siblings *sib, char* buffer) {
2461  char* ptr = buffer;
2462  ptr = Gudhi::simplex_tree::serialize_trivial(static_cast<Vertex_handle>(sib->members().size()), ptr);
2463 #ifdef DEBUG_TRACES
2464  std::clog << "\n" << sib->members().size() << " : ";
2465 #endif // DEBUG_TRACES
2466  for (auto& map_el : sib->members()) {
2467  ptr = Gudhi::simplex_tree::serialize_trivial(map_el.first, ptr); // Vertex
2468  if (Options::store_filtration)
2469  ptr = Gudhi::simplex_tree::serialize_trivial(map_el.second.filtration(), ptr); // Filtration
2470 #ifdef DEBUG_TRACES
2471  std::clog << " [ " << map_el.first << " | " << map_el.second.filtration() << " ] ";
2472 #endif // DEBUG_TRACES
2473  }
2474  for (auto& map_el : sib->members()) {
2475  if (has_children(&map_el)) {
2476  ptr = rec_serialize(map_el.second.children(), ptr);
2477  } else {
2478  ptr = Gudhi::simplex_tree::serialize_trivial(static_cast<Vertex_handle>(0), ptr);
2479 #ifdef DEBUG_TRACES
2480  std::cout << "\n0 : ";
2481 #endif // DEBUG_TRACES
2482  }
2483  }
2484  return ptr;
2485  }
2486 
2487  public:
2501  void deserialize(const char* buffer, const std::size_t buffer_size) {
2502  GUDHI_CHECK(num_vertices() == 0, std::logic_error("Simplex_tree::deserialize - Simplex_tree must be empty"));
2503  const char* ptr = buffer;
2504  // Needs to read size before recursivity to manage new siblings for children
2505  Vertex_handle members_size;
2506  ptr = Gudhi::simplex_tree::deserialize_trivial(members_size, ptr);
2507  ptr = rec_deserialize(&root_, members_size, ptr, 0);
2508  if (static_cast<std::size_t>(ptr - buffer) != buffer_size) {
2509  throw std::invalid_argument("Deserialization does not match end of buffer");
2510  }
2511  }
2512 
2513  private:
2515  const char* rec_deserialize(Siblings *sib, Vertex_handle members_size, const char* ptr, int dim) {
2516  // In case buffer is just a 0 char
2517  if (members_size > 0) {
2518  if constexpr (!Options::stable_simplex_handles) sib->members_.reserve(members_size);
2519  Vertex_handle vertex;
2521  for (Vertex_handle idx = 0; idx < members_size; idx++) {
2522  ptr = Gudhi::simplex_tree::deserialize_trivial(vertex, ptr);
2523  if (Options::store_filtration) {
2524  ptr = Gudhi::simplex_tree::deserialize_trivial(filtration, ptr);
2525  // Default is no children
2526  sib->members_.emplace_hint(sib->members_.end(), vertex, Node(sib, filtration));
2527  } else {
2528  // Default is no children
2529  sib->members_.emplace_hint(sib->members_.end(), vertex, Node(sib));
2530  }
2531  }
2532  Vertex_handle child_size;
2533  for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
2534  update_simplex_tree_after_node_insertion(sh);
2535  ptr = Gudhi::simplex_tree::deserialize_trivial(child_size, ptr);
2536  if (child_size > 0) {
2537  Siblings* child = new Siblings(sib, sh->first);
2538  sh->second.assign_children(child);
2539  ptr = rec_deserialize(child, child_size, ptr, dim + 1);
2540  }
2541  }
2542  if (dim > dimension_) {
2543  // Update dimension if needed
2544  dimension_ = dim;
2545  }
2546  }
2547  return ptr;
2548  }
2549 
2550  private:
2551  Vertex_handle null_vertex_;
2554  Siblings root_;
2556  std::vector<Simplex_handle> filtration_vect_;
2558  int dimension_;
2559  bool dimension_to_be_lowered_ = false;
2560 };
2561 
2562 // Print a Simplex_tree in os.
2563 template<typename...T>
2564 std::ostream& operator<<(std::ostream & os, Simplex_tree<T...> & st) {
2565  for (auto sh : st.filtration_simplex_range()) {
2566  os << st.dimension(sh) << " ";
2567  for (auto v : st.simplex_vertex_range(sh)) {
2568  os << v << " ";
2569  }
2570  os << st.filtration(sh) << "\n"; // TODO(VR): why adding the key ?? not read ?? << " " << st.key(sh) << " \n";
2571  }
2572  return os;
2573 }
2574 
2575 template<typename...T>
2576 std::istream& operator>>(std::istream & is, Simplex_tree<T...> & st) {
2577  typedef Simplex_tree<T...> ST;
2578  std::vector<typename ST::Vertex_handle> simplex;
2579  typename ST::Filtration_value fil;
2580  int max_dim = -1;
2581  while (read_simplex(is, simplex, fil)) {
2582  // read all simplices in the file as a list of vertices
2583  // Warning : simplex_size needs to be casted in int - Can be 0
2584  int dim = static_cast<int> (simplex.size() - 1);
2585  if (max_dim < dim) {
2586  max_dim = dim;
2587  }
2588  // insert every simplex in the simplex tree
2589  st.insert_simplex(simplex, fil);
2590  simplex.clear();
2591  }
2592  st.set_dimension(max_dim);
2593 
2594  return is;
2595 }
2596  // end addtogroup simplex_tree
2598 
2599 } // namespace Gudhi
2600 
2601 #endif // SIMPLEX_TREE_H_
Extended simplex type data structure for representing the type of simplices in an extended filtration...
Iterator over the simplices of the boundary of a simplex and their opposite vertices.
Definition: Simplex_tree_iterators.h:194
Iterator over the simplices of the boundary of a simplex.
Definition: Simplex_tree_iterators.h:82
Iterator over the simplices of a simplicial complex.
Definition: Simplex_tree_iterators.h:309
Iterator over the simplices of the star of a simplex.
Definition: Simplex_tree_star_simplex_iterators.h:162
Iterator over the vertices of a simplex in a SimplexTree.
Definition: Simplex_tree_iterators.h:37
Iterator over the simplices of the skeleton of a given dimension of the simplicial complex.
Definition: Simplex_tree_iterators.h:383
Simplex Tree data structure for representing simplicial complexes.
Definition: Simplex_tree.h:95
Simplex_tree(Simplex_tree &&complex_source)
User-defined move constructor relocates the whole tree structure.
Definition: Simplex_tree.h:414
void insert_edge_as_flag(Vertex_handle u, Vertex_handle v, Filtration_value fil, int dim_max, std::vector< Simplex_handle > &added_simplices)
Adds a new vertex or a new edge in a flag complex, as well as all simplices of its star,...
Definition: Simplex_tree.h:1407
Options::Filtration_value Filtration_value
Type for the value of the filtration function.
Definition: Simplex_tree.h:102
Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension)
Compute the cofaces of a n simplex.
Definition: Simplex_tree.h:1172
Simplex_tree_boundary_opposite_vertex_simplex_iterator< Simplex_tree > Boundary_opposite_vertex_simplex_iterator
Iterator over the simplices of the boundary of a simplex and their opposite vertices.
Definition: Simplex_tree.h:263
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:2383
void assign_filtration(Simplex_handle sh, Filtration_value fv)
Sets the filtration value of a simplex.
Definition: Simplex_tree.h:625
Simplex_tree & operator=(Simplex_tree &&complex_source)
User-defined move assignment relocates the whole tree structure.
Definition: Simplex_tree.h:448
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:942
std::vector< size_t > num_simplices_by_dimension()
Returns the number of simplices of each dimension in the simplex tree.
Definition: Simplex_tree.h:699
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:1895
Dictionary::iterator Simplex_handle
Handle type to a simplex contained in the simplicial complex represented by the simplex tree.
Definition: Simplex_tree.h:175
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:2213
bool prune_above_dimension(int dimension)
Remove all simplices of dimension greater than a given value.
Definition: Simplex_tree.h:2006
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:338
bool operator!=(Simplex_tree< OtherSimplexTreeOptions > &st2)
Checks if two simplex trees are different.
Definition: Simplex_tree.h:556
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:646
boost::iterator_range< Boundary_simplex_iterator > Boundary_simplex_range
Range over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:259
Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) const
Returns a range over the vertices of a simplex.
Definition: Simplex_tree.h:349
void for_each_simplex(Fun &&fun)
Definition: Simplex_tree.h:1859
void clear_filtration()
Clears the filtration cache produced by initialize_filtration().
Definition: Simplex_tree.h:1092
Simplex_tree_simplex_vertex_iterator< Simplex_tree > Simplex_vertex_iterator
Iterator over the vertices of a simplex.
Definition: Simplex_tree.h:241
void clear()
Remove all the simplices, leaving an empty complex.
Definition: Simplex_tree.h:1925
static Simplex_key key(Simplex_handle sh)
Returns the key associated to a simplex.
Definition: Simplex_tree.h:597
static Filtration_value filtration(Simplex_handle sh)
Returns the filtration value of a simplex.
Definition: Simplex_tree.h:614
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:913
bool operator==(Simplex_tree< OtherSimplexTreeOptions > &st2)
Checks if two simplex trees are equal.
Definition: Simplex_tree.h:547
bool has_children(SimplexHandle sh) const
Returns true if the node in the simplex tree pointed by the given simplex handle has children.
Definition: Simplex_tree.h:742
Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex)
Compute the star of a n simplex.
Definition: Simplex_tree.h:1158
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:1732
boost::iterator_range< Simplex_vertex_iterator > Simplex_vertex_range
Range over the vertices of a simplex.
Definition: Simplex_tree.h:243
void initialize_filtration(bool ignore_infinite_values=false)
Initializes the filtration cache, i.e. sorts the simplices according to their order in the filtration...
Definition: Simplex_tree.h:1055
void remove_maximal_simplex(Simplex_handle sh)
Remove a maximal simplex.
Definition: Simplex_tree.h:2087
Siblings * root()
Definition: Simplex_tree.h:1032
void assign_key(Simplex_handle sh, Simplex_key key)
Assign a value 'key' to the key of the simplex represented by the Simplex_handle 'sh'.
Definition: Simplex_tree.h:1009
Options::Simplex_key Simplex_key
Key associated to each simplex.
Definition: Simplex_tree.h:106
Simplex_tree()
Constructs an empty simplex tree.
Definition: Simplex_tree.h:397
void maybe_initialize_filtration()
Initializes the filtration cache if it isn't initialized yet.
Definition: Simplex_tree.h:1083
boost::iterator_range< Complex_simplex_iterator > Complex_simplex_range
Range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:271
Simplex_tree_boundary_simplex_iterator< Simplex_tree > Boundary_simplex_iterator
Iterator over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:257
Simplex_tree_siblings< Simplex_tree, Dictionary > Siblings
Set of nodes sharing a same parent in the simplex tree.
Definition: Simplex_tree.h:127
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:767
Boundary_opposite_vertex_simplex_range boundary_opposite_vertex_simplex_range(SimplexHandle sh)
Given a simplex, returns a range over the simplices of its boundary and their opposite vertices.
Definition: Simplex_tree.h:387
bool is_empty() const
Returns whether the complex is empty.
Definition: Simplex_tree.h:656
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:2227
Simplex_tree_complex_simplex_iterator< Simplex_tree > Complex_simplex_iterator
Iterator over the simplices of the simplicial complex.
Definition: Simplex_tree.h:269
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:2126
Simplex_handle simplex(Simplex_key idx) const
Returns the simplex that has index idx in the filtration.
Definition: Simplex_tree.h:605
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:318
boost::transform_iterator< return_first, Dictionary_it > Complex_vertex_iterator
Iterator over the vertices of the simplicial complex.
Definition: Simplex_tree.h:235
void insert_batch_vertices(VertexRange const &vertices, Filtration_value filt=0)
Inserts several vertices.
Definition: Simplex_tree.h:1335
std::vector< Simplex_handle > Filtration_simplex_range
Range over the simplices of the simplicial complex, ordered by the filtration.
Definition: Simplex_tree.h:281
Filtration_simplex_range::const_iterator Filtration_simplex_iterator
Iterator over the simplices of the simplicial complex, ordered by the filtration.
Definition: Simplex_tree.h:285
Extended_filtration_data extend_filtration()
Extend filtration for computing extended persistence. This function only uses the filtration values a...
Definition: Simplex_tree.h:2153
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:2260
Options::Vertex_handle Vertex_handle
Type for the vertex handle.
Definition: Simplex_tree.h:110
size_t num_vertices() const
Returns the number of vertices in the complex.
Definition: Simplex_tree.h:651
static Siblings * self_siblings(SimplexHandle sh)
Definition: Simplex_tree.h:1023
void expansion(int max_dim)
Expands the Simplex_tree containing only its one skeleton until dimension max_dim.
Definition: Simplex_tree.h:1360
Simplex_tree(const Simplex_tree &complex_source)
User-defined copy constructor reproduces the whole tree structure.
Definition: Simplex_tree.h:404
boost::iterator_range< Complex_vertex_iterator > Complex_vertex_range
Range over the vertices of the simplicial complex.
Definition: Simplex_tree.h:237
static Simplex_key null_key()
Returns a fixed number not in the interval [0, num_simplices()).
Definition: Simplex_tree.h:640
Boundary_simplex_range boundary_simplex_range(SimplexHandle sh)
Returns a range over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:370
int dimension(Simplex_handle sh)
Returns the dimension of a simplex.
Definition: Simplex_tree.h:720
bool prune_above_filtration(Filtration_value filtration)
Prune above filtration value given as parameter.
Definition: Simplex_tree.h:1941
int upper_bound_dimension() const
Returns an upper bound on the dimension of the simplicial complex.
Definition: Simplex_tree.h:725
std::pair< Simplex_handle, Simplex_handle > endpoints(Simplex_handle sh)
Definition: Simplex_tree.h:1016
int dimension()
Returns the dimension of the simplicial complex.
Definition: Simplex_tree.h:733
size_t num_simplices()
Returns the number of simplices in the simplex_tree.
Definition: Simplex_tree.h:664
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:276
boost::iterator_range< Boundary_opposite_vertex_simplex_iterator > Boundary_opposite_vertex_simplex_range
Range over the simplices of the boundary of a simplex and their opposite vertices.
Definition: Simplex_tree.h:265
void insert_graph(const OneSkeletonGraph &skel_graph)
Inserts a 1-skeleton in an empty Simplex_tree.
Definition: Simplex_tree.h:1272
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:279
void print_hasse(std::ostream &os)
Write the hasse diagram of the simplicial complex in os.
Definition: Simplex_tree.h:1838
~Simplex_tree()
Destructor; deallocates the whole tree structure.
Definition: Simplex_tree.h:426
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:635
Simplex_tree & operator=(const Simplex_tree &complex_source)
User-defined copy assignment reproduces the whole tree structure.
Definition: Simplex_tree.h:431
Complex_simplex_range complex_simplex_range()
Returns a range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:304
std::conditional< Options::link_nodes_by_label, Optimized_cofaces_simplex_filtered_range, std::vector< Simplex_handle > >::type Cofaces_simplex_range
Range over the cofaces of a simplex.
Definition: Simplex_tree.h:247
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:293
void set_dimension(int dimension, bool exact=true)
Set a dimension for the simplicial complex.
Definition: Simplex_tree.h:1042
Graph simplicial complex methods.
std::ostream & operator<<(std::ostream &os, const Permutahedral_representation< Vertex, OrderedSetPartition > &simplex)
Print a permutahedral representation to a stream.
Definition: Permutahedral_representation.h:173
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14
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
This file includes common file reader for GUDHI.
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20
No hook when SimplexTreeOptions::link_nodes_by_label is false.
Definition: hooks_simplex_base.h:20
Node of a simplex tree with filtration value and simplex key.
Definition: Simplex_tree_node_explicit_storage.h:38
Concept describing an indexing scheme (see FilteredComplex) for applying continuous maps to a cell co...
Definition: IndexingTag.h:18
Key type used as simplex identifier.
Definition: SimplexKey.h:15
Concept of the template parameter for the class Gudhi::Simplex_tree<SimplexTreeOptions>.
Definition: SimplexTreeOptions.h:17
static const bool store_filtration
If true, each simplex has extra storage for one Filtration_value, and this value is propagated by ope...
Definition: SimplexTreeOptions.h:32
Handle type for the vertices of a cell complex.
Definition: VertexHandle.h:15