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