summaryrefslogtreecommitdiff
path: root/src/Simplex_tree/include/gudhi/Simplex_tree.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/Simplex_tree/include/gudhi/Simplex_tree.h')
-rw-r--r--src/Simplex_tree/include/gudhi/Simplex_tree.h139
1 files changed, 107 insertions, 32 deletions
diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h
index 889dbd00..4177a0b8 100644
--- a/src/Simplex_tree/include/gudhi/Simplex_tree.h
+++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h
@@ -24,6 +24,8 @@
#include <boost/iterator/transform_iterator.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/adaptor/reversed.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+#include <boost/range/size.hpp>
#include <boost/container/static_vector.hpp>
#ifdef GUDHI_USE_TBB
@@ -42,6 +44,10 @@
namespace Gudhi {
+/** \addtogroup simplex_tree
+ * @{
+ */
+
/**
* \class Extended_simplex_type Simplex_tree.h gudhi/Simplex_tree.h
* \brief Extended simplex type data structure for representing the type of simplices in an extended filtration.
@@ -97,8 +103,7 @@ class Simplex_tree {
// Simplex_key next to each other).
typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary;
- /* \brief Set of nodes sharing a same parent in the simplex tree. */
- /* \brief Set of nodes sharing a same parent in the simplex tree. */
+ /** \brief Set of nodes sharing a same parent in the simplex tree. */
typedef Simplex_tree_siblings<Simplex_tree, Dictionary> Siblings;
@@ -187,6 +192,12 @@ class Simplex_tree {
typedef Simplex_tree_boundary_simplex_iterator<Simplex_tree> Boundary_simplex_iterator;
/** \brief Range over the simplices of the boundary of a simplex. */
typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range;
+ /** \brief Iterator over the simplices of the boundary of a simplex and their opposite vertices.
+ *
+ * 'value_type' is std::pair<Simplex_handle, Vertex_handle>. */
+ typedef Simplex_tree_boundary_opposite_vertex_simplex_iterator<Simplex_tree> Boundary_opposite_vertex_simplex_iterator;
+ /** \brief Range over the simplices of the boundary of a simplex and their opposite vertices. */
+ typedef boost::iterator_range<Boundary_opposite_vertex_simplex_iterator> Boundary_opposite_vertex_simplex_range;
/** \brief Iterator over the simplices of the simplicial complex.
*
* 'value_type' is Simplex_handle. */
@@ -296,6 +307,23 @@ class Simplex_tree {
Boundary_simplex_iterator(this));
}
+ /** \brief Given a simplex, returns a range over the simplices of its boundary and their opposite vertices.
+ *
+ * The boundary of a simplex is the set of codimension \f$1\f$ subsimplices of the simplex.
+ * If the simplex is \f$[v_0, \cdots ,v_d]\f$, with canonical orientation induced by \f$ v_0 < \cdots < v_d \f$, the
+ * iterator enumerates the simplices of the boundary in the order:
+ * \f$[v_0,\cdots,\widehat{v_i},\cdots,v_d]\f$ for \f$i\f$ from \f$d\f$ to \f$0\f$, where \f$\widehat{v_i}\f$ means
+ * that the vertex \f$v_i\f$, known as the opposite vertex, is omitted from boundary, but returned as the second
+ * element of a pair.
+ *
+ * @param[in] sh Simplex for which the boundary is computed.
+ */
+ template<class SimplexHandle>
+ Boundary_opposite_vertex_simplex_range boundary_opposite_vertex_simplex_range(SimplexHandle sh) {
+ return Boundary_opposite_vertex_simplex_range(Boundary_opposite_vertex_simplex_iterator(this, sh),
+ Boundary_opposite_vertex_simplex_iterator(this));
+ }
+
/** @} */ // end range and iterator methods
/** \name Constructor/Destructor
* @{ */
@@ -676,10 +704,10 @@ class Simplex_tree {
return true;
}
- private:
- /** \brief Inserts a simplex represented by a vector of vertex.
- * @param[in] simplex vector of Vertex_handles, representing the vertices of the new simplex. The vector must be
- * sorted by increasing vertex handle order.
+ protected:
+ /** \brief Inserts a simplex represented by a range of vertex.
+ * @param[in] simplex range of Vertex_handles, representing the vertices of the new simplex. The range must be
+ * sorted by increasing vertex handle order, and not empty.
* @param[in] filtration the filtration value assigned to the new simplex.
* @return If the new simplex is inserted successfully (i.e. it was not in the
* simplicial complex yet) the bool is set to true and the Simplex_handle is the handle assigned
@@ -691,12 +719,13 @@ class Simplex_tree {
* null_simplex.
*
*/
- std::pair<Simplex_handle, bool> insert_vertex_vector(const std::vector<Vertex_handle>& simplex,
+ template <class RandomVertexHandleRange = std::initializer_list<Vertex_handle>>
+ std::pair<Simplex_handle, bool> insert_simplex_raw(const RandomVertexHandleRange& simplex,
Filtration_value filtration) {
Siblings * curr_sib = &root_;
std::pair<Simplex_handle, bool> res_insert;
auto vi = simplex.begin();
- for (; vi != simplex.end() - 1; ++vi) {
+ for (; vi != std::prev(simplex.end()); ++vi) {
GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
if (!(has_children(res_insert.first))) {
@@ -717,9 +746,10 @@ class Simplex_tree {
return std::pair<Simplex_handle, bool>(null_simplex(), false);
}
// otherwise the insertion has succeeded - size is a size_type
- if (static_cast<int>(simplex.size()) - 1 > dimension_) {
+ int dim = static_cast<int>(boost::size(simplex)) - 1;
+ if (dim > dimension_) {
// Update dimension if needed
- dimension_ = static_cast<int>(simplex.size()) - 1;
+ dimension_ = dim;
}
return res_insert;
}
@@ -760,7 +790,7 @@ class Simplex_tree {
// Copy before sorting
std::vector<Vertex_handle> copy(first, last);
std::sort(std::begin(copy), std::end(copy));
- return insert_vertex_vector(copy, filtration);
+ return insert_simplex_raw(copy, filtration);
}
/** \brief Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of
@@ -942,7 +972,7 @@ class Simplex_tree {
// If we reached the end of the vertices, and the simplex has more vertices than the given simplex
// => we found a coface
- // Add a coface if we wan't the star or if the number of vertices of the current simplex matches with nbVertices
+ // Add a coface if we want the star or if the number of vertices of the current simplex matches with nbVertices
bool addCoface = (star || curr_nbVertices == nbVertices);
if (addCoface)
cofaces.push_back(simplex);
@@ -1060,8 +1090,8 @@ class Simplex_tree {
*
* Inserts all vertices and edges given by a OneSkeletonGraph.
* OneSkeletonGraph must be a model of
- * <a href="http://www.boost.org/doc/libs/1_65_1/libs/graph/doc/EdgeListGraph.html">boost::EdgeListGraph</a>
- * and <a href="http://www.boost.org/doc/libs/1_65_1/libs/graph/doc/PropertyGraph.html">boost::PropertyGraph</a>.
+ * <a href="https://www.boost.org/doc/libs/release/libs/graph/doc/VertexAndEdgeListGraph.html">boost::VertexAndEdgeListGraph</a>
+ * and <a href="https://www.boost.org/doc/libs/release/libs/graph/doc/PropertyGraph.html">boost::PropertyGraph</a>.
*
* The vertex filtration value is accessible through the property tag
* vertex_filtration_t.
@@ -1081,7 +1111,10 @@ class Simplex_tree {
// the simplex tree must be empty
assert(num_simplices() == 0);
- if (boost::num_vertices(skel_graph) == 0) {
+ // is there a better way to let the compiler know that we don't mean Simplex_tree::num_vertices?
+ using boost::num_vertices;
+
+ if (num_vertices(skel_graph) == 0) {
return;
}
if (num_edges(skel_graph) == 0) {
@@ -1090,25 +1123,21 @@ class Simplex_tree {
dimension_ = 1;
}
- root_.members_.reserve(boost::num_vertices(skel_graph));
+ root_.members_.reserve(num_vertices(skel_graph)); // probably useless in most cases
+ auto verts = vertices(skel_graph) | boost::adaptors::transformed([&](auto v){
+ return Dit_value_t(v, Node(&root_, get(vertex_filtration_t(), skel_graph, v))); });
+ root_.members_.insert(boost::begin(verts), boost::end(verts));
+ // This automatically sorts the vertices, the graph concept doesn't guarantee the order in which we iterate.
- typename boost::graph_traits<OneSkeletonGraph>::vertex_iterator v_it,
- v_it_end;
- for (std::tie(v_it, v_it_end) = boost::vertices(skel_graph); v_it != v_it_end;
- ++v_it) {
- root_.members_.emplace_hint(
- root_.members_.end(), *v_it,
- Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it)));
- }
std::pair<typename boost::graph_traits<OneSkeletonGraph>::edge_iterator,
- typename boost::graph_traits<OneSkeletonGraph>::edge_iterator> boost_edges = boost::edges(skel_graph);
+ typename boost::graph_traits<OneSkeletonGraph>::edge_iterator> boost_edges = edges(skel_graph);
// boost_edges.first is the equivalent to boost_edges.begin()
// boost_edges.second is the equivalent to boost_edges.end()
for (; boost_edges.first != boost_edges.second; boost_edges.first++) {
auto edge = *(boost_edges.first);
auto u = source(edge, skel_graph);
auto v = target(edge, skel_graph);
- if (u == v) throw "Self-loops are not simplicial";
+ if (u == v) throw std::invalid_argument("Self-loops are not simplicial");
// We cannot skip edges with the wrong orientation and expect them to
// come a second time with the right orientation, that does not always
// happen in practice. emplace() should be a NOP when an element with the
@@ -1123,10 +1152,25 @@ class Simplex_tree {
}
sh->second.children()->members().emplace(v,
- Node(sh->second.children(), boost::get(edge_filtration_t(), skel_graph, edge)));
+ Node(sh->second.children(), get(edge_filtration_t(), skel_graph, edge)));
}
}
+ /** \brief Inserts several vertices.
+ * @param[in] vertices A range of Vertex_handle
+ * @param[in] filt filtration value of the new vertices (the same for all)
+ *
+ * This may be faster than inserting the vertices one by one, especially in a random order.
+ * The complex does not need to be empty before calling this function. However, if a vertex is
+ * already present, its filtration value is not modified, unlike with other insertion functions. */
+ template <class VertexRange>
+ void insert_batch_vertices(VertexRange const& vertices, Filtration_value filt = 0) {
+ auto verts = vertices | boost::adaptors::transformed([&](auto v){
+ return Dit_value_t(v, Node(&root_, filt)); });
+ root_.members_.insert(boost::begin(verts), boost::end(verts));
+ if (dimension_ < 0 && !root_.members_.empty()) dimension_ = 0;
+ }
+
/** \brief Expands the Simplex_tree containing only its one skeleton
* until dimension max_dim.
*
@@ -1280,6 +1324,7 @@ class Simplex_tree {
Siblings * new_sib = new Siblings(siblings, // oncles
simplex->first, // parent
boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t
+ simplex->second.assign_children(new_sib);
std::vector<Vertex_handle> blocked_new_sib_vertex_list;
// As all intersections are inserted, we can call the blocker function on all new_sib members
for (auto new_sib_member = new_sib->members().begin();
@@ -1302,7 +1347,6 @@ class Simplex_tree {
new_sib->members().erase(blocked_new_sib_member);
}
// ensure recursive call
- simplex->second.assign_children(new_sib);
siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex);
}
} else {
@@ -1312,7 +1356,7 @@ class Simplex_tree {
}
}
- /* \private Returns the Simplex_handle composed of the vertex list (from the Simplex_handle), plus the given
+ /** \private Returns the Simplex_handle composed of the vertex list (from the Simplex_handle), plus the given
* Vertex_handle if the Vertex_handle is found in the Simplex_handle children list.
* Returns null_simplex() if it does not exist
*/
@@ -1465,7 +1509,7 @@ class Simplex_tree {
int sh_dimension = dimension(sh);
if (sh_dimension >= dimension_)
- // Stop browsing as soon as the dimension is reached, no need to go furter
+ // Stop browsing as soon as the dimension is reached, no need to go further
return false;
new_dimension = (std::max)(new_dimension, sh_dimension);
}
@@ -1569,7 +1613,7 @@ class Simplex_tree {
Simplex_tree st_copy = *this;
// Add point for coning the simplicial complex
- this->insert_simplex({maxvert}, -3);
+ this->insert_simplex_raw({maxvert}, -3);
// For each simplex
std::vector<Vertex_handle> vr;
@@ -1667,6 +1711,37 @@ class Simplex_tree {
return sh; // None of its faces has the same filtration.
}
+ public:
+ /** \brief This function resets the filtration value of all the simplices of dimension at least min_dim. Resets all
+ * the Simplex_tree when `min_dim = 0`.
+ * `reset_filtration` may break the filtration property with `min_dim > 0`, and it is the user's responsibility to
+ * make it a valid filtration (using a large enough `filt_value`, or calling `make_filtration_non_decreasing`
+ * afterwards for instance).
+ * @param[in] filt_value The new filtration value.
+ * @param[in] min_dim The minimal dimension. Default value is 0.
+ */
+ void reset_filtration(Filtration_value filt_value, int min_dim = 0) {
+ rec_reset_filtration(&root_, filt_value, min_dim);
+ clear_filtration(); // Drop the cache.
+ }
+
+ private:
+ /** \brief Recursively resets filtration value when minimal depth <= 0.
+ * @param[in] sib Siblings to be parsed.
+ * @param[in] filt_value The new filtration value.
+ * @param[in] min_depth The minimal depth.
+ */
+ void rec_reset_filtration(Siblings * sib, Filtration_value filt_value, int min_depth) {
+ for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
+ if (min_depth <= 0) {
+ sh->second.assign_filtration(filt_value);
+ }
+ if (has_children(sh)) {
+ rec_reset_filtration(sh->second.children(), filt_value, min_depth - 1);
+ }
+ }
+ }
+
private:
Vertex_handle null_vertex_;
/** \brief Total number of simplices in the complex, without the empty simplex.*/
@@ -1744,7 +1819,7 @@ struct Simplex_tree_options_fast_persistence {
static const bool contiguous_vertices = true;
};
-/** @} */ // end defgroup simplex_tree
+/** @}*/ // end addtogroup simplex_tree
} // namespace Gudhi