Loading...
Searching...
No Matches
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
61namespace Gudhi {
62
79enum class Extended_simplex_type {UP, DOWN, EXTRA};
80
94template<typename SimplexTreeOptions = Simplex_tree_options_default>
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
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
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
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();
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) {
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());
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();
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
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);
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.
2563template<typename...T>
2564std::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
2575template<typename...T>
2576std::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
Data structure to store a set of nodes in a SimplexTree sharing the same parent node.
Definition: Simplex_tree_siblings.h:31
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
static Siblings * self_siblings(SimplexHandle sh)
Definition: Simplex_tree.h:1023
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
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
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
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 prune_above_dimension(int dimension)
Remove all simplices of dimension greater than a given value.
Definition: Simplex_tree.h:2006
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 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
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
std::pair< Simplex_handle, Simplex_handle > endpoints(Simplex_handle sh)
Definition: Simplex_tree.h:1016
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
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
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
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
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
size_t num_vertices() const
Returns the number of vertices in the complex.
Definition: Simplex_tree.h:651
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
Siblings * root()
Definition: Simplex_tree.h:1032
int dimension()
Returns the dimension of the simplicial complex.
Definition: Simplex_tree.h:733
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
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
Simplex_tree & operator=(Simplex_tree &&complex_source)
User-defined move assignment relocates the whole tree structure.
Definition: Simplex_tree.h:448
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
Simplex_tree & operator=(const Simplex_tree &complex_source)
User-defined copy assignment reproduces the whole tree structure.
Definition: Simplex_tree.h:431
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
Complex_simplex_range complex_simplex_range()
Returns a range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:304
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
This file includes common file reader for GUDHI.
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
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
static const bool link_nodes_by_label
If true, the lists of Node with same label are stored to enhance cofaces and stars access.
Definition: SimplexTreeOptions.h:37
static const bool stable_simplex_handles
If true, Simplex_handle will not be invalidated after insertions or removals.
Definition: SimplexTreeOptions.h:39
static constexpr bool contiguous_vertices
If true, the list of vertices present in the complex must always be 0, ..., num_vertices-1,...
Definition: SimplexTreeOptions.h:35
Handle type for the vertices of a cell complex.
Definition: VertexHandle.h:15