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 * - 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/range/adaptor/transformed.hpp>
28#include <boost/range/size.hpp>
29#include <boost/container/static_vector.hpp>
30
31#ifdef GUDHI_USE_TBB
32#include <tbb/parallel_sort.h>
33#endif
34
35#include <utility>
36#include <vector>
37#include <functional> // for greater<>
38#include <stdexcept>
39#include <limits> // Inf
40#include <initializer_list>
41#include <algorithm> // for std::max
42#include <cstdint> // for std::uint32_t
43#include <iterator> // for std::distance
44
45namespace Gudhi {
46
63enum class Extended_simplex_type {UP, DOWN, EXTRA};
64
65struct Simplex_tree_options_full_featured;
66
80template<typename SimplexTreeOptions = Simplex_tree_options_full_featured>
82 public:
84 typedef typename Options::Indexing_tag Indexing_tag;
97
98 /* Type of node in the simplex tree. */
100 /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
101 // Note: this wastes space when Vertex_handle is 32 bits and Node is aligned on 64 bits. It would be better to use a
102 // flat_set (with our own comparator) where we can control the layout of the struct (put Vertex_handle and
103 // Simplex_key next to each other).
104 typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary;
105
108
109
110
111 struct Key_simplex_base_real {
112 Key_simplex_base_real() : key_(-1) {}
113 void assign_key(Simplex_key k) { key_ = k; }
114 Simplex_key key() const { return key_; }
115 private:
116 Simplex_key key_;
117 };
118 struct Key_simplex_base_dummy {
119 Key_simplex_base_dummy() {}
120 // Undefined so it will not link
121 void assign_key(Simplex_key);
122 Simplex_key key() const;
123 };
124 struct Extended_filtration_data {
125 Filtration_value minval;
126 Filtration_value maxval;
127 Extended_filtration_data(){}
128 Extended_filtration_data(Filtration_value vmin, Filtration_value vmax): minval(vmin), maxval(vmax) {}
129 };
130 typedef typename std::conditional<Options::store_key, Key_simplex_base_real, Key_simplex_base_dummy>::type
131 Key_simplex_base;
132
133 struct Filtration_simplex_base_real {
134 Filtration_simplex_base_real() : filt_(0) {}
135 void assign_filtration(Filtration_value f) { filt_ = f; }
136 Filtration_value filtration() const { return filt_; }
137 private:
138 Filtration_value filt_;
139 };
140 struct Filtration_simplex_base_dummy {
141 Filtration_simplex_base_dummy() {}
142 void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); }
143 Filtration_value filtration() const { return 0; }
144 };
145 typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real,
146 Filtration_simplex_base_dummy>::type Filtration_simplex_base;
147
148 public:
154 typedef typename Dictionary::iterator Simplex_handle;
155
156 private:
157 typedef typename Dictionary::iterator Dictionary_it;
158 typedef typename Dictionary_it::value_type Dit_value_t;
159
160 struct return_first {
161 Vertex_handle operator()(const Dit_value_t& p_sh) const {
162 return p_sh.first;
163 }
164 };
165
166 public:
178 typedef boost::transform_iterator<return_first, Dictionary_it> Complex_vertex_iterator;
180 typedef boost::iterator_range<Complex_vertex_iterator> Complex_vertex_range;
186 typedef boost::iterator_range<Simplex_vertex_iterator> Simplex_vertex_range;
188 typedef std::vector<Simplex_handle> Cofaces_simplex_range;
194 typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range;
200 typedef boost::iterator_range<Boundary_opposite_vertex_simplex_iterator> Boundary_opposite_vertex_simplex_range;
206 typedef boost::iterator_range<Complex_simplex_iterator> Complex_simplex_range;
214 typedef boost::iterator_range<Skeleton_simplex_iterator> Skeleton_simplex_range;
216 typedef std::vector<Simplex_handle> Filtration_simplex_range;
220 typedef typename Filtration_simplex_range::const_iterator Filtration_simplex_iterator;
221
222 /* @} */ // end name range and iterator types
230 boost::make_transform_iterator(root_.members_.begin(), return_first()),
231 boost::make_transform_iterator(root_.members_.end(), return_first()));
232 }
233
242 }
243
256 }
257
275 return filtration_vect_;
276 }
277
285 GUDHI_CHECK(sh != null_simplex(), "empty simplex");
288 }
289
304 template<class SimplexHandle>
308 }
309
321 template<class SimplexHandle>
325 }
326 // end range and iterator methods
333 : null_vertex_(-1),
334 root_(nullptr, null_vertex_),
335 filtration_vect_(),
336 dimension_(-1) { }
337
339 Simplex_tree(const Simplex_tree& complex_source) {
340#ifdef DEBUG_TRACES
341 std::clog << "Simplex_tree copy constructor" << std::endl;
342#endif // DEBUG_TRACES
343 copy_from(complex_source);
344 }
345
349 Simplex_tree(Simplex_tree && complex_source) {
350#ifdef DEBUG_TRACES
351 std::clog << "Simplex_tree move constructor" << std::endl;
352#endif // DEBUG_TRACES
353 move_from(complex_source);
354
355 // just need to set dimension_ on source to make it available again
356 // (filtration_vect_ and members are already set from the move)
357 complex_source.dimension_ = -1;
358 }
359
362 root_members_recursive_deletion();
363 }
364
366 Simplex_tree& operator= (const Simplex_tree& complex_source) {
367#ifdef DEBUG_TRACES
368 std::clog << "Simplex_tree copy assignment" << std::endl;
369#endif // DEBUG_TRACES
370 // Self-assignment detection
371 if (&complex_source != this) {
372 // We start by deleting root_ if not empty
373 root_members_recursive_deletion();
374
375 copy_from(complex_source);
376 }
377 return *this;
378 }
379
384#ifdef DEBUG_TRACES
385 std::clog << "Simplex_tree move assignment" << std::endl;
386#endif // DEBUG_TRACES
387 // Self-assignment detection
388 if (&complex_source != this) {
389 // root_ deletion in case it was not empty
390 root_members_recursive_deletion();
391
392 move_from(complex_source);
393 }
394 return *this;
395 } // end constructor/destructor
397
398 private:
399 // Copy from complex_source to "this"
400 void copy_from(const Simplex_tree& complex_source) {
401 null_vertex_ = complex_source.null_vertex_;
402 filtration_vect_.clear();
403 dimension_ = complex_source.dimension_;
404 auto root_source = complex_source.root_;
405
406 // root members copy
407 root_.members() = Dictionary(boost::container::ordered_unique_range, root_source.members().begin(), root_source.members().end());
408 // Needs to reassign children
409 for (auto& map_el : root_.members()) {
410 map_el.second.assign_children(&root_);
411 }
412 rec_copy(&root_, &root_source);
413 }
414
416 void rec_copy(Siblings *sib, Siblings *sib_source) {
417 for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin();
418 sh != sib->members().end(); ++sh, ++sh_source) {
419 if (has_children(sh_source)) {
420 Siblings * newsib = new Siblings(sib, sh_source->first);
421 newsib->members_.reserve(sh_source->second.children()->members().size());
422 for (auto & child : sh_source->second.children()->members())
423 newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(newsib, child.second.filtration()));
424 rec_copy(newsib, sh_source->second.children());
425 sh->second.assign_children(newsib);
426 }
427 }
428 }
429
430 // Move from complex_source to "this"
431 void move_from(Simplex_tree& complex_source) {
432 null_vertex_ = std::move(complex_source.null_vertex_);
433 root_ = std::move(complex_source.root_);
434 filtration_vect_ = std::move(complex_source.filtration_vect_);
435 dimension_ = std::move(complex_source.dimension_);
436
437 // Need to update root members (children->oncles and children need to point on the new root pointer)
438 for (auto& map_el : root_.members()) {
439 if (map_el.second.children() != &(complex_source.root_)) {
440 // reset children->oncles with the moved root_ pointer value
441 map_el.second.children()->oncles_ = &root_;
442 } else {
443 // if simplex is of dimension 0, oncles_ shall be nullptr
444 GUDHI_CHECK(map_el.second.children()->oncles_ == nullptr,
445 std::invalid_argument("Simplex_tree move constructor from an invalid Simplex_tree"));
446 // and children points on root_ - to be moved
447 map_el.second.assign_children(&root_);
448 }
449 }
450 }
451
452 // delete all root_.members() recursively
453 void root_members_recursive_deletion() {
454 for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh) {
455 if (has_children(sh)) {
456 rec_delete(sh->second.children());
457 }
458 }
459 root_.members().clear();
460 }
461
462 // Recursive deletion
463 void rec_delete(Siblings * sib) {
464 for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
465 if (has_children(sh)) {
466 rec_delete(sh->second.children());
467 }
468 }
469 delete sib;
470 }
471
472 public:
475 if ((null_vertex_ != st2.null_vertex_) ||
476 (dimension_ != st2.dimension_))
477 return false;
478 return rec_equal(&root_, &st2.root_);
479 }
480
483 return (!(*this == st2));
484 }
485
486 private:
488 bool rec_equal(Siblings* s1, Siblings* s2) {
489 if (s1->members().size() != s2->members().size())
490 return false;
491 for (auto sh1 = s1->members().begin(), sh2 = s2->members().begin();
492 (sh1 != s1->members().end() && sh2 != s2->members().end()); ++sh1, ++sh2) {
493 if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration())
494 return false;
495 if (has_children(sh1) != has_children(sh2))
496 return false;
497 // Recursivity on children only if both have children
498 else if (has_children(sh1))
499 if (!rec_equal(sh1->second.children(), sh2->second.children()))
500 return false;
501 }
502 return true;
503 }
504
509 static Filtration_value filtration_(Simplex_handle sh) {
510 GUDHI_CHECK (sh != null_simplex(), "null simplex");
511 return sh->second.filtration();
512 }
513
514 public:
521 return sh->second.key();
522 }
523
529 return filtration_vect_[idx];
530 }
531
538 if (sh != null_simplex()) {
539 return sh->second.filtration();
540 } else {
541 return std::numeric_limits<Filtration_value>::infinity();
542 }
543 }
544
549 GUDHI_CHECK(sh != null_simplex(),
550 std::invalid_argument("Simplex_tree::assign_filtration - cannot assign filtration on null_simplex"));
551 sh->second.assign_filtration(fv);
552 }
553
559 return Dictionary_it(nullptr);
560 }
561
564 return -1;
565 }
566
570 return null_vertex_;
571 }
572
574 size_t num_vertices() const {
575 return root_.members_.size();
576 }
577
578 public:
580 size_t num_simplices() {
581 return num_simplices(&root_);
582 }
583
584 private:
586 size_t num_simplices(Siblings * sib) {
587 auto sib_begin = sib->members().begin();
588 auto sib_end = sib->members().end();
589 size_t simplices_number = sib_end - sib_begin;
590 for (auto sh = sib_begin; sh != sib_end; ++sh) {
591 if (has_children(sh)) {
592 simplices_number += num_simplices(sh->second.children());
593 }
594 }
595 return simplices_number;
596 }
597
598 public:
603 Siblings * curr_sib = self_siblings(sh);
604 int dim = 0;
605 while (curr_sib != nullptr) {
606 ++dim;
607 curr_sib = curr_sib->oncles();
608 }
609 return dim - 1;
610 }
611
614 return dimension_;
615 }
616
621 int dimension() {
622 if (dimension_to_be_lowered_)
623 lower_upper_bound_dimension();
624 return dimension_;
625 }
626
629 template<class SimplexHandle>
630 bool has_children(SimplexHandle sh) const {
631 // Here we rely on the root using null_vertex(), which cannot match any real vertex.
632 return (sh->second.children()->parent() == sh->first);
633 }
634
642 template<class InputVertexRange = std::initializer_list<Vertex_handle>>
643 Simplex_handle find(const InputVertexRange & s) {
644 auto first = std::begin(s);
645 auto last = std::end(s);
646
647 if (first == last)
648 return null_simplex(); // ----->>
649
650 // Copy before sorting
651 std::vector<Vertex_handle> copy(first, last);
652 std::sort(std::begin(copy), std::end(copy));
653 return find_simplex(copy);
654 }
655
656 private:
658 Simplex_handle find_simplex(const std::vector<Vertex_handle> & simplex) {
659 Siblings * tmp_sib = &root_;
660 Dictionary_it tmp_dit;
661 auto vi = simplex.begin();
663 // Equivalent to the first iteration of the normal loop
664 GUDHI_CHECK(contiguous_vertices(), "non-contiguous vertices");
665 Vertex_handle v = *vi++;
666 if(v < 0 || v >= static_cast<Vertex_handle>(root_.members_.size()))
667 return null_simplex();
668 tmp_dit = root_.members_.begin() + v;
669 if (vi == simplex.end())
670 return tmp_dit;
671 if (!has_children(tmp_dit))
672 return null_simplex();
673 tmp_sib = tmp_dit->second.children();
674 }
675 for (;;) {
676 tmp_dit = tmp_sib->members_.find(*vi++);
677 if (tmp_dit == tmp_sib->members_.end())
678 return null_simplex();
679 if (vi == simplex.end())
680 return tmp_dit;
681 if (!has_children(tmp_dit))
682 return null_simplex();
683 tmp_sib = tmp_dit->second.children();
684 }
685 }
686
689 Simplex_handle find_vertex(Vertex_handle v) {
691 assert(contiguous_vertices());
692 return root_.members_.begin() + v;
693 } else {
694 return root_.members_.find(v);
695 }
696 }
697
698 public:
700 bool contiguous_vertices() const {
701 if (root_.members_.empty()) return true;
702 if (root_.members_.begin()->first != 0) return false;
703 if (std::prev(root_.members_.end())->first != static_cast<Vertex_handle>(root_.members_.size() - 1)) return false;
704 return true;
705 }
706
707 protected:
722 template <class RandomVertexHandleRange = std::initializer_list<Vertex_handle>>
723 std::pair<Simplex_handle, bool> insert_simplex_raw(const RandomVertexHandleRange& simplex,
725 Siblings * curr_sib = &root_;
726 std::pair<Simplex_handle, bool> res_insert;
727 auto vi = simplex.begin();
728 for (; vi != std::prev(simplex.end()); ++vi) {
729 GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
730 res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
731 if (!(has_children(res_insert.first))) {
732 res_insert.first->second.assign_children(new Siblings(curr_sib, *vi));
733 }
734 curr_sib = res_insert.first->second.children();
735 }
736 GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
737 res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
738 if (!res_insert.second) {
739 // if already in the complex
740 if (res_insert.first->second.filtration() > filtration) {
741 // if filtration value modified
742 res_insert.first->second.assign_filtration(filtration);
743 return res_insert;
744 }
745 // if filtration value unchanged
746 return std::pair<Simplex_handle, bool>(null_simplex(), false);
747 }
748 // otherwise the insertion has succeeded - size is a size_type
749 int dim = static_cast<int>(boost::size(simplex)) - 1;
750 if (dim > dimension_) {
751 // Update dimension if needed
752 dimension_ = dim;
753 }
754 return res_insert;
755 }
756
757 public:
781 template<class InputVertexRange = std::initializer_list<Vertex_handle>>
782 std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex,
784 auto first = std::begin(simplex);
785 auto last = std::end(simplex);
786
787 if (first == last)
788 return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->>
789
790 // Copy before sorting
791 std::vector<Vertex_handle> copy(first, last);
792 std::sort(std::begin(copy), std::end(copy));
793 return insert_simplex_raw(copy, filtration);
794 }
795
810 template<class InputVertexRange = std::initializer_list<Vertex_handle>>
811 std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex,
813 auto first = std::begin(Nsimplex);
814 auto last = std::end(Nsimplex);
815
816 if (first == last)
817 return { null_simplex(), true }; // FIXME: false would make more sense to me.
818
819 thread_local std::vector<Vertex_handle> copy;
820 copy.clear();
821 copy.insert(copy.end(), first, last);
822 std::sort(copy.begin(), copy.end());
823 auto last_unique = std::unique(copy.begin(), copy.end());
824 copy.erase(last_unique, copy.end());
825 GUDHI_CHECK_code(
826 for (Vertex_handle v : copy)
827 GUDHI_CHECK(v != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
828 )
829 // Update dimension if needed. We could wait to see if the insertion succeeds, but I doubt there is much to gain.
830 dimension_ = (std::max)(dimension_, static_cast<int>(std::distance(copy.begin(), copy.end())) - 1);
831
832 return rec_insert_simplex_and_subfaces_sorted(root(), copy.begin(), copy.end(), filtration);
833 }
834
835 private:
836 // To insert {1,2,3,4}, we insert {2,3,4} twice, once at the root, and once below 1.
837 template<class ForwardVertexIterator>
838 std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces_sorted(Siblings* sib,
839 ForwardVertexIterator first,
840 ForwardVertexIterator last,
841 Filtration_value filt) {
842 // An alternative strategy would be:
843 // - try to find the complete simplex, if found (and low filtration) exit
844 // - insert all the vertices at once in sib
845 // - loop over those (new or not) simplices, with a recursive call(++first, last)
846 Vertex_handle vertex_one = *first;
847 auto&& dict = sib->members();
848 auto insertion_result = dict.emplace(vertex_one, Node(sib, filt));
849 Simplex_handle simplex_one = insertion_result.first;
850 bool one_is_new = insertion_result.second;
851 if (!one_is_new) {
852 if (filtration(simplex_one) > filt) {
853 assign_filtration(simplex_one, filt);
854 } else {
855 // FIXME: this interface makes no sense, and it doesn't seem to be tested.
856 insertion_result.first = null_simplex();
857 }
858 }
859 if (++first == last) return insertion_result;
860 if (!has_children(simplex_one))
861 // TODO: have special code here, we know we are building the whole subtree from scratch.
862 simplex_one->second.assign_children(new Siblings(sib, vertex_one));
863 auto res = rec_insert_simplex_and_subfaces_sorted(simplex_one->second.children(), first, last, filt);
864 // No need to continue if the full simplex was already there with a low enough filtration value.
865 if (res.first != null_simplex()) rec_insert_simplex_and_subfaces_sorted(sib, first, last, filt);
866 return res;
867 }
868
869 public:
873 sh->second.assign_key(key);
874 }
875
879 std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) {
880 assert(dimension(sh) == 1);
881 return { find_vertex(sh->first), find_vertex(self_siblings(sh)->parent()) };
882 }
883
885 template<class SimplexHandle>
886 static Siblings* self_siblings(SimplexHandle sh) {
887 if (sh->second.children()->parent() == sh->first)
888 return sh->second.children()->oncles();
889 else
890 return sh->second.children();
891 }
892
893 public:
896 return &root_;
897 }
898
904 dimension_to_be_lowered_ = false;
905 dimension_ = dimension;
906 }
907
908 public:
917 filtration_vect_.clear();
918 filtration_vect_.reserve(num_simplices());
920 filtration_vect_.push_back(sh);
921
922 /* We use stable_sort here because with libstdc++ it is faster than sort.
923 * is_before_in_filtration is now a total order, but we used to call
924 * stable_sort for the following heuristic:
925 * The use of a depth-first traversal of the simplex tree, provided by
926 * complex_simplex_range(), combined with a stable sort is meant to
927 * optimize the order of simplices with same filtration value. The
928 * heuristic consists in inserting the cofaces of a simplex as soon as
929 * possible.
930 */
931#ifdef GUDHI_USE_TBB
932 tbb::parallel_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
933#else
934 std::stable_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
935#endif
936 }
941 if (filtration_vect_.empty()) {
943 }
944 }
950 filtration_vect_.clear();
951 }
952
953 private:
966 void rec_coface(std::vector<Vertex_handle> &vertices, Siblings *curr_sib, int curr_nbVertices,
967 std::vector<Simplex_handle>& cofaces, bool star, int nbVertices) {
968 if (!(star || curr_nbVertices <= nbVertices)) // dimension of actual simplex <= nbVertices
969 return;
970 for (Simplex_handle simplex = curr_sib->members().begin(); simplex != curr_sib->members().end(); ++simplex) {
971 if (vertices.empty()) {
972 // If we reached the end of the vertices, and the simplex has more vertices than the given simplex
973 // => we found a coface
974
975 // Add a coface if we want the star or if the number of vertices of the current simplex matches with nbVertices
976 bool addCoface = (star || curr_nbVertices == nbVertices);
977 if (addCoface)
978 cofaces.push_back(simplex);
979 if ((!addCoface || star) && has_children(simplex)) // Rec call
980 rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
981 } else {
982 if (simplex->first == vertices.back()) {
983 // If curr_sib matches with the top vertex
984 bool equalDim = (star || curr_nbVertices == nbVertices); // dimension of actual simplex == nbVertices
985 bool addCoface = vertices.size() == 1 && equalDim;
986 if (addCoface)
987 cofaces.push_back(simplex);
988 if ((!addCoface || star) && has_children(simplex)) {
989 // Rec call
990 Vertex_handle tmp = vertices.back();
991 vertices.pop_back();
992 rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
993 vertices.push_back(tmp);
994 }
995 } else if (simplex->first > vertices.back()) {
996 return;
997 } else {
998 // (simplex->first < vertices.back()
1000 rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
1001 }
1002 }
1003 }
1004 }
1005
1006 public:
1013 return cofaces_simplex_range(simplex, 0);
1014 }
1015
1024 Cofaces_simplex_range cofaces;
1025 // codimension must be positive or null integer
1026 assert(codimension >= 0);
1028 std::vector<Vertex_handle> copy(rg.begin(), rg.end());
1029 if (codimension + static_cast<int>(copy.size()) > dimension_ + 1 ||
1030 (codimension == 0 && static_cast<int>(copy.size()) > dimension_)) // n+codimension greater than dimension_
1031 return cofaces;
1032 // must be sorted in decreasing order
1033 assert(std::is_sorted(copy.begin(), copy.end(), std::greater<Vertex_handle>()));
1034 bool star = codimension == 0;
1035 rec_coface(copy, &root_, 1, cofaces, star, codimension + static_cast<int>(copy.size()));
1036 return cofaces;
1037 }
1038
1039 private:
1047 bool reverse_lexicographic_order(Simplex_handle sh1, Simplex_handle sh2) {
1050 Simplex_vertex_iterator it1 = rg1.begin();
1051 Simplex_vertex_iterator it2 = rg2.begin();
1052 while (it1 != rg1.end() && it2 != rg2.end()) {
1053 if (*it1 == *it2) {
1054 ++it1;
1055 ++it2;
1056 } else {
1057 return *it1 < *it2;
1058 }
1059 }
1060 return ((it1 == rg1.end()) && (it2 != rg2.end()));
1061 }
1062
1069 struct is_before_in_filtration {
1070 explicit is_before_in_filtration(Simplex_tree * st)
1071 : st_(st) { }
1072
1073 bool operator()(const Simplex_handle sh1, const Simplex_handle sh2) const {
1074 // Not using st_->filtration(sh1) because it uselessly tests for null_simplex.
1075 if (sh1->second.filtration() != sh2->second.filtration()) {
1076 return sh1->second.filtration() < sh2->second.filtration();
1077 }
1078 // is sh1 a proper subface of sh2
1079 return st_->reverse_lexicographic_order(sh1, sh2);
1080 }
1081
1082 Simplex_tree * st_;
1083 };
1084
1085 public:
1109 template<class OneSkeletonGraph>
1110 void insert_graph(const OneSkeletonGraph& skel_graph) {
1111 // the simplex tree must be empty
1112 assert(num_simplices() == 0);
1113
1114 // is there a better way to let the compiler know that we don't mean Simplex_tree::num_vertices?
1115 using boost::num_vertices;
1116
1117 if (num_vertices(skel_graph) == 0) {
1118 return;
1119 }
1120 if (num_edges(skel_graph) == 0) {
1121 dimension_ = 0;
1122 } else {
1123 dimension_ = 1;
1124 }
1125
1126 root_.members_.reserve(num_vertices(skel_graph)); // probably useless in most cases
1127 auto verts = vertices(skel_graph) | boost::adaptors::transformed([&](auto v){
1128 return Dit_value_t(v, Node(&root_, get(vertex_filtration_t(), skel_graph, v))); });
1129 root_.members_.insert(boost::begin(verts), boost::end(verts));
1130 // This automatically sorts the vertices, the graph concept doesn't guarantee the order in which we iterate.
1131
1132 std::pair<typename boost::graph_traits<OneSkeletonGraph>::edge_iterator,
1133 typename boost::graph_traits<OneSkeletonGraph>::edge_iterator> boost_edges = edges(skel_graph);
1134 // boost_edges.first is the equivalent to boost_edges.begin()
1135 // boost_edges.second is the equivalent to boost_edges.end()
1136 for (; boost_edges.first != boost_edges.second; boost_edges.first++) {
1137 auto edge = *(boost_edges.first);
1138 auto u = source(edge, skel_graph);
1139 auto v = target(edge, skel_graph);
1140 if (u == v) throw std::invalid_argument("Self-loops are not simplicial");
1141 // We cannot skip edges with the wrong orientation and expect them to
1142 // come a second time with the right orientation, that does not always
1143 // happen in practice. emplace() should be a NOP when an element with the
1144 // same key is already there, so seeing the same edge multiple times is
1145 // ok.
1146 // Should we actually forbid multiple edges? That would be consistent
1147 // with rejecting self-loops.
1148 if (v < u) std::swap(u, v);
1149 auto sh = find_vertex(u);
1150 if (!has_children(sh)) {
1151 sh->second.assign_children(new Siblings(&root_, sh->first));
1152 }
1153
1154 sh->second.children()->members().emplace(v,
1155 Node(sh->second.children(), get(edge_filtration_t(), skel_graph, edge)));
1156 }
1157 }
1158
1166 template <class VertexRange>
1167 void insert_batch_vertices(VertexRange const& vertices, Filtration_value filt = 0) {
1168 auto verts = vertices | boost::adaptors::transformed([&](auto v){
1169 return Dit_value_t(v, Node(&root_, filt)); });
1170 root_.members_.insert(boost::begin(verts), boost::end(verts));
1171 if (dimension_ < 0 && !root_.members_.empty()) dimension_ = 0;
1172 }
1173
1185 void expansion(int max_dim) {
1186 if (max_dim <= 1) return;
1187 clear_filtration(); // Drop the cache.
1188 dimension_ = max_dim;
1189 for (Dictionary_it root_it = root_.members_.begin();
1190 root_it != root_.members_.end(); ++root_it) {
1191 if (has_children(root_it)) {
1192 siblings_expansion(root_it->second.children(), max_dim - 1);
1193 }
1194 }
1195 dimension_ = max_dim - dimension_;
1196 }
1197
1198 private:
1200 void siblings_expansion(Siblings * siblings, // must contain elements
1201 int k) {
1202 if (dimension_ > k) {
1203 dimension_ = k;
1204 }
1205 if (k == 0)
1206 return;
1207 Dictionary_it next = siblings->members().begin();
1208 ++next;
1209
1210 thread_local std::vector<std::pair<Vertex_handle, Node> > inter;
1211 for (Dictionary_it s_h = siblings->members().begin();
1212 s_h != siblings->members().end(); ++s_h, ++next) {
1213 Simplex_handle root_sh = find_vertex(s_h->first);
1214 if (has_children(root_sh)) {
1215 intersection(
1216 inter, // output intersection
1217 next, // begin
1218 siblings->members().end(), // end
1219 root_sh->second.children()->members().begin(),
1220 root_sh->second.children()->members().end(),
1221 s_h->second.filtration());
1222 if (inter.size() != 0) {
1223 Siblings * new_sib = new Siblings(siblings, // oncles
1224 s_h->first, // parent
1225 inter); // boost::container::ordered_unique_range_t
1226 inter.clear();
1227 s_h->second.assign_children(new_sib);
1228 siblings_expansion(new_sib, k - 1);
1229 } else {
1230 // ensure the children property
1231 s_h->second.assign_children(siblings);
1232 inter.clear();
1233 }
1234 }
1235 }
1236 }
1237
1240 static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection,
1241 Dictionary_it begin1, Dictionary_it end1,
1242 Dictionary_it begin2, Dictionary_it end2,
1243 Filtration_value filtration_) {
1244 if (begin1 == end1 || begin2 == end2)
1245 return; // ----->>
1246 while (true) {
1247 if (begin1->first == begin2->first) {
1248 Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_});
1249 intersection.emplace_back(begin1->first, Node(nullptr, filt));
1250 if (++begin1 == end1 || ++begin2 == end2)
1251 return; // ----->>
1252 } else if (begin1->first < begin2->first) {
1253 if (++begin1 == end1)
1254 return;
1255 } else /* begin1->first > begin2->first */ {
1256 if (++begin2 == end2)
1257 return; // ----->>
1258 }
1259 }
1260 }
1261
1262 public:
1281 template< typename Blocker >
1282 void expansion_with_blockers(int max_dim, Blocker block_simplex) {
1283 // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1284 for (auto& simplex : boost::adaptors::reverse(root_.members())) {
1285 if (has_children(&simplex)) {
1286 siblings_expansion_with_blockers(simplex.second.children(), max_dim, max_dim - 1, block_simplex);
1287 }
1288 }
1289 }
1290
1291 private:
1293 template< typename Blocker >
1294 void siblings_expansion_with_blockers(Siblings* siblings, int max_dim, int k, Blocker block_simplex) {
1295 if (dimension_ < max_dim - k) {
1296 dimension_ = max_dim - k;
1297 }
1298 if (k == 0)
1299 return;
1300 // No need to go deeper
1301 if (siblings->members().size() < 2)
1302 return;
1303 // Reverse loop starting before the last one for 'next' to be the last one
1304 for (auto simplex = siblings->members().rbegin() + 1; simplex != siblings->members().rend(); simplex++) {
1305 std::vector<std::pair<Vertex_handle, Node> > intersection;
1306 for(auto next = siblings->members().rbegin(); next != simplex; next++) {
1307 bool to_be_inserted = true;
1308 Filtration_value filt = simplex->second.filtration();
1309 // If all the boundaries are present, 'next' needs to be inserted
1310 for (Simplex_handle border : boundary_simplex_range(simplex)) {
1311 Simplex_handle border_child = find_child(border, next->first);
1312 if (border_child == null_simplex()) {
1313 to_be_inserted=false;
1314 break;
1315 }
1316 filt = (std::max)(filt, filtration(border_child));
1317 }
1318 if (to_be_inserted) {
1319 intersection.emplace_back(next->first, Node(nullptr, filt));
1320 }
1321 }
1322 if (intersection.size() != 0) {
1323 // Reverse the order to insert
1324 Siblings * new_sib = new Siblings(siblings, // oncles
1325 simplex->first, // parent
1326 boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t
1327 simplex->second.assign_children(new_sib);
1328 std::vector<Vertex_handle> blocked_new_sib_vertex_list;
1329 // As all intersections are inserted, we can call the blocker function on all new_sib members
1330 for (auto new_sib_member = new_sib->members().begin();
1331 new_sib_member != new_sib->members().end();
1332 new_sib_member++) {
1333 bool blocker_result = block_simplex(new_sib_member);
1334 // new_sib member has been blocked by the blocker function
1335 // add it to the list to be removed - do not perform it while looping on it
1336 if (blocker_result) {
1337 blocked_new_sib_vertex_list.push_back(new_sib_member->first);
1338 }
1339 }
1340 if (blocked_new_sib_vertex_list.size() == new_sib->members().size()) {
1341 // Specific case where all have to be deleted
1342 delete new_sib;
1343 // ensure the children property
1344 simplex->second.assign_children(siblings);
1345 } else {
1346 for (auto& blocked_new_sib_member : blocked_new_sib_vertex_list) {
1347 new_sib->members().erase(blocked_new_sib_member);
1348 }
1349 // ensure recursive call
1350 siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex);
1351 }
1352 } else {
1353 // ensure the children property
1354 simplex->second.assign_children(siblings);
1355 }
1356 }
1357 }
1358
1363 Simplex_handle find_child(Simplex_handle sh, Vertex_handle vh) const {
1364 if (!has_children(sh))
1365 return null_simplex();
1366
1367 Simplex_handle child = sh->second.children()->find(vh);
1368 // Specific case of boost::flat_map does not find, returns boost::flat_map::end()
1369 // in simplex tree we want a null_simplex()
1370 if (child == sh->second.children()->members().end())
1371 return null_simplex();
1372
1373 return child;
1374 }
1375
1376 public:
1383 void print_hasse(std::ostream& os) {
1384 os << num_simplices() << " " << std::endl;
1385 for (auto sh : filtration_simplex_range()) {
1386 os << dimension(sh) << " ";
1387 for (auto b_sh : boundary_simplex_range(sh)) {
1388 os << key(b_sh) << " ";
1389 }
1390 os << filtration(sh) << " \n";
1391 }
1392 }
1393
1394 public:
1402 bool modified = false;
1403 // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1404 for (auto& simplex : boost::adaptors::reverse(root_.members())) {
1405 if (has_children(&simplex)) {
1406 modified |= rec_make_filtration_non_decreasing(simplex.second.children());
1407 }
1408 }
1409 if(modified)
1410 clear_filtration(); // Drop the cache.
1411 return modified;
1412 }
1413
1414 private:
1419 bool rec_make_filtration_non_decreasing(Siblings * sib) {
1420 bool modified = false;
1421
1422 // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
1423 for (auto& simplex : boost::adaptors::reverse(sib->members())) {
1424 // Find the maximum filtration value in the border
1426 Boundary_simplex_iterator max_border = std::max_element(std::begin(boundary), std::end(boundary),
1427 [](Simplex_handle sh1, Simplex_handle sh2) {
1428 return filtration(sh1) < filtration(sh2);
1429 });
1430
1431 Filtration_value max_filt_border_value = filtration(*max_border);
1432 // Replacing if(f<max) with if(!(f>=max)) would mean that if f is NaN, we replace it with the max of the children.
1433 // That seems more useful than keeping NaN.
1434 if (!(simplex.second.filtration() >= max_filt_border_value)) {
1435 // Store the filtration modification information
1436 modified = true;
1437 simplex.second.assign_filtration(max_filt_border_value);
1438 }
1439 if (has_children(&simplex)) {
1440 modified |= rec_make_filtration_non_decreasing(simplex.second.children());
1441 }
1442 }
1443 // Make the modified information to be traced by upper call
1444 return modified;
1445 }
1446
1447 public:
1456 bool modified = rec_prune_above_filtration(root(), filtration);
1457 if(modified)
1458 clear_filtration(); // Drop the cache.
1459 return modified;
1460 }
1461
1462 private:
1463 bool rec_prune_above_filtration(Siblings* sib, Filtration_value filt) {
1464 auto&& list = sib->members();
1465 auto last = std::remove_if(list.begin(), list.end(), [this,filt](Dit_value_t& simplex) {
1466 if (simplex.second.filtration() <= filt) return false;
1467 if (has_children(&simplex)) rec_delete(simplex.second.children());
1468 // dimension may need to be lowered
1469 dimension_to_be_lowered_ = true;
1470 return true;
1471 });
1472
1473 bool modified = (last != list.end());
1474 if (last == list.begin() && sib != root()) {
1475 // Removing the whole siblings, parent becomes a leaf.
1476 sib->oncles()->members()[sib->parent()].assign_children(sib->oncles());
1477 delete sib;
1478 // dimension may need to be lowered
1479 dimension_to_be_lowered_ = true;
1480 return true;
1481 } else {
1482 // Keeping some elements of siblings. Remove the others, and recurse in the remaining ones.
1483 list.erase(last, list.end());
1484 for (auto&& simplex : list)
1485 if (has_children(&simplex))
1486 modified |= rec_prune_above_filtration(simplex.second.children(), filt);
1487 }
1488 return modified;
1489 }
1490
1491 private:
1497 bool lower_upper_bound_dimension() {
1498 // reset automatic detection to recompute
1499 dimension_to_be_lowered_ = false;
1500 int new_dimension = -1;
1501 // Browse the tree from the left to the right as higher dimension cells are more likely on the left part of the tree
1502 for (Simplex_handle sh : complex_simplex_range()) {
1503#ifdef DEBUG_TRACES
1504 for (auto vertex : simplex_vertex_range(sh)) {
1505 std::clog << " " << vertex;
1506 }
1507 std::clog << std::endl;
1508#endif // DEBUG_TRACES
1509
1510 int sh_dimension = dimension(sh);
1511 if (sh_dimension >= dimension_)
1512 // Stop browsing as soon as the dimension is reached, no need to go further
1513 return false;
1514 new_dimension = (std::max)(new_dimension, sh_dimension);
1515 }
1516 dimension_ = new_dimension;
1517 return true;
1518 }
1519
1520
1521 public:
1531 // Guarantee the simplex has no children
1532 GUDHI_CHECK(!has_children(sh),
1533 std::invalid_argument("Simplex_tree::remove_maximal_simplex - argument has children"));
1534
1535 // Simplex is a leaf, it means the child is the Siblings owning the leaf
1536 Siblings* child = sh->second.children();
1537
1538 if ((child->size() > 1) || (child == root())) {
1539 // Not alone, just remove it from members
1540 // Special case when child is the root of the simplex tree, just remove it from members
1541 child->erase(sh);
1542 } else {
1543 // Sibling is emptied : must be deleted, and its parent must point on his own Sibling
1544 child->oncles()->members().at(child->parent()).assign_children(child->oncles());
1545 delete child;
1546 // dimension may need to be lowered
1547 dimension_to_be_lowered_ = true;
1548 }
1549 }
1550
1567 std::pair<Filtration_value, Extended_simplex_type> decode_extended_filtration(Filtration_value f, const Extended_filtration_data& efd){
1568 std::pair<Filtration_value, Extended_simplex_type> p;
1569 Filtration_value minval = efd.minval;
1570 Filtration_value maxval = efd.maxval;
1571 if (f >= -2 && f <= -1){
1572 p.first = minval + (maxval-minval)*(f + 2); p.second = Extended_simplex_type::UP;
1573 }
1574 else if (f >= 1 && f <= 2){
1575 p.first = minval - (maxval-minval)*(f - 2); p.second = Extended_simplex_type::DOWN;
1576 }
1577 else{
1578 p.first = std::numeric_limits<Filtration_value>::quiet_NaN(); p.second = Extended_simplex_type::EXTRA;
1579 }
1580 return p;
1581 };
1582
1596 Extended_filtration_data extend_filtration() {
1597 clear_filtration(); // Drop the cache.
1598
1599 // Compute maximum and minimum of filtration values
1600 Vertex_handle maxvert = std::numeric_limits<Vertex_handle>::min();
1601 Filtration_value minval = std::numeric_limits<Filtration_value>::infinity();
1602 Filtration_value maxval = -std::numeric_limits<Filtration_value>::infinity();
1603 for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh){
1604 Filtration_value f = this->filtration(sh);
1605 minval = std::min(minval, f);
1606 maxval = std::max(maxval, f);
1607 maxvert = std::max(sh->first, maxvert);
1608 }
1609
1610 GUDHI_CHECK(maxvert < std::numeric_limits<Vertex_handle>::max(), std::invalid_argument("Simplex_tree contains a vertex with the largest Vertex_handle"));
1611 maxvert += 1;
1612
1613 Simplex_tree st_copy = *this;
1614
1615 // Add point for coning the simplicial complex
1616 this->insert_simplex_raw({maxvert}, -3);
1617
1618 // For each simplex
1619 std::vector<Vertex_handle> vr;
1620 for (auto sh_copy : st_copy.complex_simplex_range()){
1621
1622 // Locate simplex
1623 vr.clear();
1624 for (auto vh : st_copy.simplex_vertex_range(sh_copy)){
1625 vr.push_back(vh);
1626 }
1627 auto sh = this->find(vr);
1628
1629 // Create cone on simplex
1630 vr.push_back(maxvert);
1631 if (this->dimension(sh) == 0){
1632 Filtration_value v = this->filtration(sh);
1633 Filtration_value scaled_v = (v-minval)/(maxval-minval);
1634 // Assign ascending value between -2 and -1 to vertex
1635 this->assign_filtration(sh, -2 + scaled_v);
1636 // Assign descending value between 1 and 2 to cone on vertex
1637 this->insert_simplex(vr, 2 - scaled_v);
1638 }
1639 else{
1640 // Assign value -3 to simplex and cone on simplex
1641 this->assign_filtration(sh, -3);
1642 this->insert_simplex(vr, -3);
1643 }
1644 }
1645
1646 // Automatically assign good values for simplices
1648
1649 // Return the filtration data
1650 Extended_filtration_data efd(minval, maxval);
1651 return efd;
1652 }
1653
1659 auto filt = filtration_(sh);
1660 for(auto v : simplex_vertex_range(sh))
1661 if(filtration_(find_vertex(v)) == filt)
1662 return v;
1663 return null_vertex();
1664 }
1665
1673 // See issue #251 for potential speed improvements.
1674 auto&& vertices = simplex_vertex_range(sh); // vertices in decreasing order
1675 auto end = std::end(vertices);
1676 auto vi = std::begin(vertices);
1677 GUDHI_CHECK(vi != end, "empty simplex");
1678 auto v0 = *vi;
1679 ++vi;
1680 GUDHI_CHECK(vi != end, "simplex of dimension 0");
1681 if(std::next(vi) == end) return sh; // shortcut for dimension 1
1682 boost::container::static_vector<Vertex_handle, 40> suffix;
1683 suffix.push_back(v0);
1684 auto filt = filtration_(sh);
1685 do
1686 {
1687 Vertex_handle v = *vi;
1688 auto&& children1 = find_vertex(v)->second.children()->members_;
1689 for(auto w : suffix){
1690 // Can we take advantage of the fact that suffix is ordered?
1691 Simplex_handle s = children1.find(w);
1692 if(filtration_(s) == filt)
1693 return s;
1694 }
1695 suffix.push_back(v);
1696 }
1697 while(++vi != end);
1698 return null_simplex();
1699 }
1700
1706 auto filt = filtration_(sh);
1707 // Naive implementation, it can be sped up.
1708 for(auto b : boundary_simplex_range(sh))
1709 if(filtration_(b) == filt)
1711 return sh; // None of its faces has the same filtration.
1712 }
1713
1714 public:
1723 void reset_filtration(Filtration_value filt_value, int min_dim = 0) {
1724 rec_reset_filtration(&root_, filt_value, min_dim);
1725 clear_filtration(); // Drop the cache.
1726 }
1727
1728 private:
1734 void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int min_depth) {
1735 for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
1736 if (min_depth <= 0) {
1737 sh->second.assign_filtration(filt_value);
1738 }
1739 if (has_children(sh)) {
1740 rec_reset_filtration(sh->second.children(), filt_value, min_depth - 1);
1741 }
1742 }
1743 }
1744
1745 private:
1746 Vertex_handle null_vertex_;
1749 Siblings root_;
1751 std::vector<Simplex_handle> filtration_vect_;
1753 int dimension_;
1754 bool dimension_to_be_lowered_ = false;
1755};
1756
1757// Print a Simplex_tree in os.
1758template<typename...T>
1759std::ostream& operator<<(std::ostream & os, Simplex_tree<T...> & st) {
1760 for (auto sh : st.filtration_simplex_range()) {
1761 os << st.dimension(sh) << " ";
1762 for (auto v : st.simplex_vertex_range(sh)) {
1763 os << v << " ";
1764 }
1765 os << st.filtration(sh) << "\n"; // TODO(VR): why adding the key ?? not read ?? << " " << st.key(sh) << " \n";
1766 }
1767 return os;
1768}
1769
1770template<typename...T>
1771std::istream& operator>>(std::istream & is, Simplex_tree<T...> & st) {
1772 typedef Simplex_tree<T...> ST;
1773 std::vector<typename ST::Vertex_handle> simplex;
1774 typename ST::Filtration_value fil;
1775 int max_dim = -1;
1776 while (read_simplex(is, simplex, fil)) {
1777 // read all simplices in the file as a list of vertices
1778 // Warning : simplex_size needs to be casted in int - Can be 0
1779 int dim = static_cast<int> (simplex.size() - 1);
1780 if (max_dim < dim) {
1781 max_dim = dim;
1782 }
1783 // insert every simplex in the simplex tree
1784 st.insert_simplex(simplex, fil);
1785 simplex.clear();
1786 }
1787 st.set_dimension(max_dim);
1788
1789 return is;
1790}
1791
1798 typedef int Vertex_handle;
1799 typedef double Filtration_value;
1800 typedef std::uint32_t Simplex_key;
1801 static const bool store_key = true;
1802 static const bool store_filtration = true;
1803 static const bool contiguous_vertices = false;
1804};
1805
1814 typedef int Vertex_handle;
1815 typedef float Filtration_value;
1816 typedef std::uint32_t Simplex_key;
1817 static const bool store_key = true;
1818 static const bool store_filtration = true;
1819 static const bool contiguous_vertices = true;
1820};
1821 // end addtogroup simplex_tree
1823
1824} // namespace Gudhi
1825
1826#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:190
Iterator over the simplices of the boundary of a simplex.
Definition: Simplex_tree_iterators.h:83
Iterator over the simplices of a simplicial complex.
Definition: Simplex_tree_iterators.h:300
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:38
Iterator over the simplices of the skeleton of a given dimension of the simplicial complex.
Definition: Simplex_tree_iterators.h:374
Simplex Tree data structure for representing simplicial complexes.
Definition: Simplex_tree.h:81
static Siblings * self_siblings(SimplexHandle sh)
Definition: Simplex_tree.h:886
Simplex_tree(Simplex_tree &&complex_source)
User-defined move constructor relocates the whole tree structure.
Definition: Simplex_tree.h:349
bool operator==(Simplex_tree &st2)
Checks if two simplex trees are equal.
Definition: Simplex_tree.h:474
Options::Filtration_value Filtration_value
Type for the value of the filtration function.
Definition: Simplex_tree.h:88
Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension)
Compute the cofaces of a n simplex.
Definition: Simplex_tree.h:1023
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:198
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:1723
void assign_filtration(Simplex_handle sh, Filtration_value fv)
Sets the filtration value of a simplex.
Definition: Simplex_tree.h:548
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:1401
Dictionary::iterator Simplex_handle
Handle type to a simplex contained in the simplicial complex represented by the simplex tree.
Definition: Simplex_tree.h:154
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:1658
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:273
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:782
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:569
boost::iterator_range< Boundary_simplex_iterator > Boundary_simplex_range
Range over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:194
Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) const
Returns a range over the vertices of a simplex.
Definition: Simplex_tree.h:284
void clear_filtration()
Clears the filtration cache produced by initialize_filtration().
Definition: Simplex_tree.h:949
Simplex_tree_simplex_vertex_iterator< Simplex_tree > Simplex_vertex_iterator
Iterator over the vertices of a simplex.
Definition: Simplex_tree.h:184
static Simplex_key key(Simplex_handle sh)
Returns the key associated to a simplex.
Definition: Simplex_tree.h:520
static Filtration_value filtration(Simplex_handle sh)
Returns the filtration value of a simplex.
Definition: Simplex_tree.h:537
bool operator!=(Simplex_tree &st2)
Checks if two simplex trees are different.
Definition: Simplex_tree.h:482
bool has_children(SimplexHandle sh) const
Returns true if the node in the simplex tree pointed by sh has children.
Definition: Simplex_tree.h:630
Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex)
Compute the star of a n simplex.
Definition: Simplex_tree.h:1012
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:1282
boost::iterator_range< Simplex_vertex_iterator > Simplex_vertex_range
Range over the vertices of a simplex.
Definition: Simplex_tree.h:186
void remove_maximal_simplex(Simplex_handle sh)
Remove a maximal simplex.
Definition: Simplex_tree.h:1530
std::pair< Simplex_handle, Simplex_handle > endpoints(Simplex_handle sh)
Definition: Simplex_tree.h:879
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:872
Options::Simplex_key Simplex_key
Key associated to each simplex.
Definition: Simplex_tree.h:92
Simplex_tree()
Constructs an empty simplex tree.
Definition: Simplex_tree.h:332
void maybe_initialize_filtration()
Initializes the filtration cache if it isn't initialized yet.
Definition: Simplex_tree.h:940
boost::iterator_range< Complex_simplex_iterator > Complex_simplex_range
Range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:206
Simplex_tree_boundary_simplex_iterator< Simplex_tree > Boundary_simplex_iterator
Iterator over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:192
Simplex_tree_siblings< Simplex_tree, Dictionary > Siblings
Set of nodes sharing a same parent in the simplex tree.
Definition: Simplex_tree.h:107
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:643
std::vector< Simplex_handle > Cofaces_simplex_range
Range over the cofaces of a simplex.
Definition: Simplex_tree.h:188
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:322
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:1672
Simplex_tree_complex_simplex_iterator< Simplex_tree > Complex_simplex_iterator
Iterator over the simplices of the simplicial complex.
Definition: Simplex_tree.h:204
Simplex_handle simplex(Simplex_key idx) const
Returns the simplex that has index idx in the filtration.
Definition: Simplex_tree.h:528
void initialize_filtration()
Initializes the filtration cache, i.e. sorts the simplices according to their order in the filtration...
Definition: Simplex_tree.h:916
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:253
boost::transform_iterator< return_first, Dictionary_it > Complex_vertex_iterator
Iterator over the vertices of the simplicial complex.
Definition: Simplex_tree.h:178
void insert_batch_vertices(VertexRange const &vertices, Filtration_value filt=0)
Inserts several vertices.
Definition: Simplex_tree.h:1167
std::vector< Simplex_handle > Filtration_simplex_range
Range over the simplices of the simplicial complex, ordered by the filtration.
Definition: Simplex_tree.h:216
Filtration_simplex_range::const_iterator Filtration_simplex_iterator
Iterator over the simplices of the simplicial complex, ordered by the filtration.
Definition: Simplex_tree.h:220
Extended_filtration_data extend_filtration()
Extend filtration for computing extended persistence. This function only uses the filtration values a...
Definition: Simplex_tree.h:1596
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:1705
Options::Vertex_handle Vertex_handle
Type for the vertex handle.
Definition: Simplex_tree.h:96
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:1567
size_t num_vertices() const
Returns the number of vertices in the complex.
Definition: Simplex_tree.h:574
void expansion(int max_dim)
Expands the Simplex_tree containing only its one skeleton until dimension max_dim.
Definition: Simplex_tree.h:1185
Simplex_tree(const Simplex_tree &complex_source)
User-defined copy constructor reproduces the whole tree structure.
Definition: Simplex_tree.h:339
boost::iterator_range< Complex_vertex_iterator > Complex_vertex_range
Range over the vertices of the simplicial complex.
Definition: Simplex_tree.h:180
static Simplex_key null_key()
Returns a fixed number not in the interval [0, num_simplices()).
Definition: Simplex_tree.h:563
Boundary_simplex_range boundary_simplex_range(SimplexHandle sh)
Returns a range over the simplices of the boundary of a simplex.
Definition: Simplex_tree.h:305
int dimension(Simplex_handle sh)
Returns the dimension of a simplex.
Definition: Simplex_tree.h:602
bool prune_above_filtration(Filtration_value filtration)
Prune above filtration value given as parameter.
Definition: Simplex_tree.h:1455
int upper_bound_dimension() const
Returns an upper bound on the dimension of the simplicial complex.
Definition: Simplex_tree.h:613
Siblings * root()
Definition: Simplex_tree.h:895
int dimension()
Returns the dimension of the simplicial complex.
Definition: Simplex_tree.h:621
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:811
size_t num_simplices()
returns the number of simplices in the simplex_tree.
Definition: Simplex_tree.h:580
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:211
Simplex_tree & operator=(Simplex_tree &&complex_source)
User-defined move assignment relocates the whole tree structure.
Definition: Simplex_tree.h:383
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:200
Simplex_tree & operator=(const Simplex_tree &complex_source)
User-defined copy assignment reproduces the whole tree structure.
Definition: Simplex_tree.h:366
void insert_graph(const OneSkeletonGraph &skel_graph)
Inserts a 1-skeleton in an empty Simplex_tree.
Definition: Simplex_tree.h:1110
void set_dimension(int dimension)
Set a dimension for the simplicial complex.
Definition: Simplex_tree.h:903
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:214
void print_hasse(std::ostream &os)
Write the hasse diagram of the simplicial complex in os.
Definition: Simplex_tree.h:1383
~Simplex_tree()
Destructor; deallocates the whole tree structure.
Definition: Simplex_tree.h:361
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:558
Complex_simplex_range complex_simplex_range()
Returns a range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:239
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:228
Graph simplicial complex methods.
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
Node of a simplex tree with filtration value and simplex key.
Definition: Simplex_tree_node_explicit_storage.h:29
Definition: Simplex_tree.h:1812
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
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:27
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:29
Handle type for the vertices of a cell complex.
Definition: VertexHandle.h:15