summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Tangential_complex/example/example_basic.cpp5
-rw-r--r--src/Toplex_map/benchmark/CMakeLists.txt4
-rw-r--r--src/Toplex_map/benchmark/chrono.cpp139
-rw-r--r--src/Toplex_map/doc/Intro_Toplex_map.h62
-rw-r--r--src/Toplex_map/doc/map.pngbin0 -> 278692 bytes
-rw-r--r--src/Toplex_map/example/CMakeLists.txt5
-rw-r--r--src/Toplex_map/example/Fake_simplex_tree.h188
-rw-r--r--src/Toplex_map/example/Simple_toplex_map.cpp218
-rw-r--r--src/Toplex_map/example/Toplex_map_from_cliques_of_graph.cpp93
-rw-r--r--src/Toplex_map/include/gudhi/Filtered_toplex_map.h84
-rw-r--r--src/Toplex_map/include/gudhi/Lazy_Toplex_map.h263
-rw-r--r--src/Toplex_map/include/gudhi/Toplex_map.h322
-rw-r--r--src/Toplex_map/test/CMakeLists.txt14
-rw-r--r--src/Toplex_map/test/toplex_map_unit_test.cpp54
-rw-r--r--src/common/doc/main_page.h17
17 files changed, 1469 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 76e5b528..9b97947f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,7 @@ add_gudhi_module(Skeleton_blocker)
add_gudhi_module(Spatial_searching)
add_gudhi_module(Subsampling)
add_gudhi_module(Tangential_complex)
+add_gudhi_module(Toplex_map)
add_gudhi_module(Witness_complex)
add_gudhi_module(Nerve_GIC)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b40d506a..40fdcf2b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,6 +35,7 @@ add_gudhi_module(Skeleton_blocker)
add_gudhi_module(Spatial_searching)
add_gudhi_module(Subsampling)
add_gudhi_module(Tangential_complex)
+add_gudhi_module(Toplex_map)
add_gudhi_module(Witness_complex)
add_gudhi_module(Nerve_GIC)
diff --git a/src/Tangential_complex/example/example_basic.cpp b/src/Tangential_complex/example/example_basic.cpp
index 4f2b859e..ab35edf0 100644
--- a/src/Tangential_complex/example/example_basic.cpp
+++ b/src/Tangential_complex/example/example_basic.cpp
@@ -1,5 +1,7 @@
#include <gudhi/Tangential_complex.h>
#include <gudhi/sparsify_point_set.h>
+//#include <gudhi/Fake_simplex_tree.h>
+
#include <CGAL/Epick_d.h>
#include <CGAL/Random.h>
@@ -20,7 +22,7 @@ CGAL::Parallel_tag> TC;
int main(void) {
const int INTRINSIC_DIM = 2;
const int AMBIENT_DIM = 3;
- const int NUM_POINTS = 1000;
+ const int NUM_POINTS = 100;
Kernel k;
@@ -37,6 +39,7 @@ int main(void) {
// Export the TC into a Simplex_tree
Gudhi::Simplex_tree<> stree;
+ //Gudhi::Fake_simplex_tree stree;
tc.create_complex(stree);
// Display stats about inconsistencies
diff --git a/src/Toplex_map/benchmark/CMakeLists.txt b/src/Toplex_map/benchmark/CMakeLists.txt
new file mode 100644
index 00000000..2c67892c
--- /dev/null
+++ b/src/Toplex_map/benchmark/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.6)
+project(Toplex_map_benchmark)
+
+add_executable(toplex_map_chrono chrono.cpp)
diff --git a/src/Toplex_map/benchmark/chrono.cpp b/src/Toplex_map/benchmark/chrono.cpp
new file mode 100644
index 00000000..a745f099
--- /dev/null
+++ b/src/Toplex_map/benchmark/chrono.cpp
@@ -0,0 +1,139 @@
+#include <iostream>
+#include <random>
+#include <chrono>
+
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Toplex_map.h>
+#include <gudhi/Lazy_Toplex_map.h>
+
+using namespace Gudhi;
+
+typedef Toplex_map::Simplex Simplex;
+typedef Toplex_map::Vertex Vertex;
+typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
+
+class ST_wrapper {
+
+public:
+ void insert_simplex(const Simplex& tau);
+ bool membership(const Simplex& tau);
+ Vertex contraction(const Vertex x, const Vertex y);
+ std::size_t num_simplices();
+
+private:
+ Simplex_tree<> simplexTree;
+ void erase_max(const Simplex& sigma);
+};
+
+void ST_wrapper::insert_simplex(const Simplex& tau){
+ simplexTree.insert_simplex_and_subfaces(tau);
+}
+
+bool ST_wrapper::membership(const Simplex& tau) {
+ return simplexTree.find(tau) != simplexTree.null_simplex();
+}
+
+void ST_wrapper::erase_max(const Simplex& sigma){
+ if(membership(sigma))
+ simplexTree.remove_maximal_simplex(simplexTree.find(sigma));
+}
+
+Vertex ST_wrapper::contraction(const Vertex x, const Vertex y){
+ Simplex sx; sx.insert(x);
+ auto hx = simplexTree.find(sx);
+ if(hx != simplexTree.null_simplex())
+ for(auto h : simplexTree.cofaces_simplex_range(hx,0)){
+ auto sr = simplexTree.simplex_vertex_range(h);
+ Simplex sigma(sr.begin(),sr.end());
+ erase_max(sigma);
+ sigma.erase(x);
+ sigma.insert(y);
+ insert_simplex(sigma);
+ }
+ return y;
+}
+
+std::size_t ST_wrapper::num_simplices(){
+ return simplexTree.num_simplices();
+}
+
+
+
+int n = 300;
+
+int nb_insert_simplex1 = 3000;
+int nb_membership1 = 4000;
+int nb_contraction = 300;
+int nb_insert_simplex2 = 3000;
+int nb_membership2 = 400000;
+
+Simplex random_simplex(int n, std::size_t d){
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<std::size_t> dis(1, n);
+ Simplex s;
+ while(s.size()!=d)
+ s.insert(dis(gen));
+ return s;
+}
+
+std::vector<Simplex> r_vector_simplices(int n, int max_d, int m){
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<std::size_t> dis(1, max_d);
+ std::vector<Simplex> v;
+ for(int i=0; i<m; i++)
+ v.push_back(random_simplex(n,dis(gen)));
+ return v;
+}
+
+template<typename complex_type>
+void chrono(int n, int d){
+ complex_type K;
+ std::vector<Simplex> simplices_insert_simplex1 = r_vector_simplices(n,d,nb_insert_simplex1);
+ std::vector<Simplex> simplices_membership1 = r_vector_simplices(n,d,nb_membership1);
+ std::vector<Simplex> simplices_insert_simplex2 = r_vector_simplices(n - 2*nb_contraction,d,nb_insert_simplex2);
+ std::vector<Simplex> simplices_membership2 = r_vector_simplices(n - 2*nb_contraction,d,nb_membership2);
+ std::chrono::time_point<std::chrono::system_clock> start, end;
+
+ for(const Simplex& s : simplices_insert_simplex1)
+ K.insert_simplex(s);
+
+ for(const Simplex& s : simplices_membership1)
+ K.membership(s);
+
+ start = std::chrono::system_clock::now();
+ for(int i = 0; i<=nb_contraction; i++)
+ K.contraction(n-2*i,n-2*i-1);
+ end = std::chrono::system_clock::now();
+ auto c3 = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
+
+ start = std::chrono::system_clock::now();
+ for(const Simplex& s : simplices_insert_simplex2)
+ K.insert_simplex(s);
+ end = std::chrono::system_clock::now();
+ auto c1 = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
+
+ start = std::chrono::system_clock::now();
+ for(const Simplex& s : simplices_membership2)
+ K.membership(s);
+ end = std::chrono::system_clock::now();
+ auto c2 = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
+
+ std::cout << c1 << "\t \t" << c2 << "\t \t" << c3 << "\t \t" << K.num_simplices() << std::endl;
+}
+
+int main(){
+ for(int d=5;d<=40;d+=5){
+ std::cout << "d=" << d << " \t Insertions \t Membership \t Contractions \t Size" << std::endl;
+ std::cout << "T Map \t \t";
+ chrono<Toplex_map>(n,d);
+ std::cout << "Lazy \t \t";
+ chrono<Lazy_Toplex_map>(n,d);
+ if(d<=15){
+ std::cout << "ST \t \t";
+ chrono<ST_wrapper>(n,d);
+ }
+ std::cout << std::endl;
+ }
+}
diff --git a/src/Toplex_map/doc/Intro_Toplex_map.h b/src/Toplex_map/doc/Intro_Toplex_map.h
new file mode 100644
index 00000000..e3f18b32
--- /dev/null
+++ b/src/Toplex_map/doc/Intro_Toplex_map.h
@@ -0,0 +1,62 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author: François Godi
+ *
+ * Copyright (C) 2017 INRIA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DOC_TOPLEX_MAP_H_
+#define DOC_TOPLEX_MAP_H_
+
+// needs namespace for Doxygen to link on classes
+namespace Gudhi {
+
+/** \defgroup toplex_map Toplex Map
+ *
+ * \author Fran&ccedil;ois Godi
+ * @{
+ *
+ * \section toplexmapdefinition Definition
+ *
+ * Let's consider a simplicial complex, denote by \f$d\f$ its dimension
+ * and by \f$k\f$ its number of maximal simplices.
+ * Furthermore, denote by \f$\gamma_0\f$ the maximal number of toplices, i.e. maximal simplices,
+ * that contain a same vertex.
+ *
+ * The goal of the Toplex Map is both to represent the complex in optimal
+ * O(kd) space and to provide fast standard operations such as : insertion, removal
+ * and membership of a simplex, contraction of an edge, collapses. The time needed
+ * for these operation is linear or quadratic in \f$\gamma_0\f$ and \f$d\f$.
+ *
+ * Toplex map is composed firstly of a raw storage of toplices and secondly of a
+ * map which associate any vertex to a set of pointers toward all toplices
+ * containing this vertex.
+ *
+ * \image html map.png
+ *
+ * The performances are a lot better than in simplex tree as soon you use maximal simplices and not simplices,
+ * here the construction of a strong witness complex of a point set with growing parameter :
+ *
+ * \image html graph.png
+ *
+ */
+/** @} */ // end defgroup toplex_map
+
+} // namespace Gudhi
+
+#endif // DOC_TOPLEX_MAP_H_
diff --git a/src/Toplex_map/doc/map.png b/src/Toplex_map/doc/map.png
new file mode 100644
index 00000000..d1987043
--- /dev/null
+++ b/src/Toplex_map/doc/map.png
Binary files differ
diff --git a/src/Toplex_map/example/CMakeLists.txt b/src/Toplex_map/example/CMakeLists.txt
new file mode 100644
index 00000000..051d7bcd
--- /dev/null
+++ b/src/Toplex_map/example/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.6)
+project(Toplex_map_examples)
+
+add_executable(Toplex_map_example_simple Simple_toplex_map.cpp)
+add_executable(Toplex_map_example_from_cliques_of_graph Toplex_map_from_cliques_of_graph.cpp)
diff --git a/src/Toplex_map/example/Fake_simplex_tree.h b/src/Toplex_map/example/Fake_simplex_tree.h
new file mode 100644
index 00000000..6a7e7bdc
--- /dev/null
+++ b/src/Toplex_map/example/Fake_simplex_tree.h
@@ -0,0 +1,188 @@
+#ifndef FAKE_SIMPLEX_TREE_H
+#define FAKE_SIMPLEX_TREE_H
+
+#include <cmath>
+
+#include <gudhi/Simplex_tree.h>
+#include <gudhi/Filtered_toplex_map.h>
+
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/bron_kerbosch_all_cliques.hpp>
+
+namespace Gudhi {
+
+struct Visitor {
+ Toplex_map* tm;
+
+ Visitor(Toplex_map* tm)
+ :tm(tm)
+ {}
+
+ template <typename Clique, typename Graph>
+ void clique(const Clique& c, const Graph& g)
+ {
+ tm->insert_simplex(c);
+ }
+};
+
+/** Fake_simplex_tree is a wrapper for Filtered_toplex_map which has the interface of the Simplex_tree.
+ * Mostly for retro-compatibility purpose. If you use a function that output non maximal simplices, it will be non efficient.
+ * \ingroup toplex_map */
+class Fake_simplex_tree : public Filtered_toplex_map {
+
+public:
+
+ /** Handle type to a vertex contained in the simplicial complex.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Vertex Vertex_handle;
+
+ /** Handle type to a simplex contained in the simplicial complex.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex Simplex_handle;
+
+ typedef void Insertion_result_type;
+
+ /** Inserts the flag complex of a given range `Gudhi::rips_complex::Rips_complex::OneSkeletonGraph`
+ * in the simplicial complex.
+ * \ingroup toplex_map */
+ template<class OneSkeletonGraph>
+ void insert_graph(const OneSkeletonGraph& skel_graph);
+
+ /** Do actually nothing.
+ * \ingroup toplex_map */
+ void expansion(int max_dim);
+
+ /** Returns the number of vertices stored i.e. the number of max simplices
+ * \ingroup toplex_map */
+ std::size_t num_vertices() const;
+
+ /** Returns the dimension of the complex.
+ * \ingroup toplex_map */
+ std::size_t dimension() const;
+
+ /** Returns the dimension of a given simplex in the complex.
+ * \ingroup toplex_map */
+ std::size_t dimension(Simplex_ptr& sptr) const;
+
+ /** Returns the number of simplices stored i.e. the number of maximal simplices.
+ * \ingroup toplex_map */
+ std::size_t num_simplices() const;
+
+ /** Returns a range over the vertices of a simplex.
+ * \ingroup toplex_map */
+ Toplex_map::Simplex simplex_vertex_range(const Simplex& s) const;
+
+ /** Returns a set of all maximal (critical if there is filtration values) simplices.
+ * \ingroup toplex_map */
+ std::vector<Toplex_map::Simplex> max_simplices() const;
+
+ /** Returns all the simplices, of max dimension d if a parameter d is given.
+ * \ingroup toplex_map */
+ std::vector<Toplex_map::Simplex> filtration_simplex_range(int d=std::numeric_limits<int>::max()) const;
+
+ /** Returns all the simplices of max dimension d
+ * \ingroup toplex_map */
+ std::vector<Toplex_map::Simplex> skeleton_simplex_range(int d) const;
+
+ Toplex_map::Vertex contraction(const Toplex_map::Vertex x, const Toplex_map::Vertex y);
+
+
+protected:
+
+ /** \internal Does all the facets of the given simplex belong to the complex ?
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool all_facets_inside(const Input_vertex_range &vertex_range) const;
+
+};
+
+template<class OneSkeletonGraph>
+void Fake_simplex_tree::insert_graph(const OneSkeletonGraph& skel_graph){
+ toplex_maps.emplace(nan(""), new Toplex_map());
+ using vertex_iterator = typename boost::graph_traits<OneSkeletonGraph>::vertex_iterator;
+ vertex_iterator vi, vi_end;
+ for (std::tie(vi, vi_end) = boost::vertices(skel_graph); vi != vi_end; ++vi) {
+ Simplex s; s.insert(*vi);
+ insert_simplex_and_subfaces(s);
+ }
+ bron_kerbosch_all_cliques(skel_graph, Visitor(this->toplex_maps.at(nan(""))));
+}
+
+void Fake_simplex_tree::expansion(int max_dim){}
+
+template <typename Input_vertex_range>
+bool Fake_simplex_tree::all_facets_inside(const Input_vertex_range &vertex_range) const{
+ Simplex sigma(vertex_range);
+ for(const Simplex& s : facets(sigma))
+ if(!membership(s)) return false;
+ return true;
+}
+
+std::size_t Fake_simplex_tree::dimension() const {
+ std::size_t max = 0;
+ for(const Simplex& s : max_simplices())
+ max = std::max(max, s.size());
+ return max-1;
+}
+
+std::size_t Fake_simplex_tree::dimension(Simplex_ptr& sptr) const{
+ return sptr->size();
+}
+
+std::size_t Fake_simplex_tree::num_simplices() const {
+ return max_simplices().size();
+}
+
+std::size_t Fake_simplex_tree::num_vertices() const {
+ std::unordered_set<Toplex_map::Vertex> vertices;
+ for(const Toplex_map::Simplex& s : max_simplices())
+ for (Toplex_map::Vertex v : s)
+ vertices.emplace(v);
+ return vertices.size();
+}
+
+Toplex_map::Simplex Fake_simplex_tree::simplex_vertex_range(const Simplex& s) const {
+ return s;
+}
+
+std::vector<Toplex_map::Simplex> Fake_simplex_tree::max_simplices() const{
+ std::vector<Toplex_map::Simplex> max_s;
+ for(auto kv : toplex_maps)
+ for(const Toplex_map::Simplex_ptr& sptr : kv.second->maximal_cofaces(Simplex()))
+ max_s.emplace_back(*sptr);
+ return max_s;
+}
+
+std::vector<Toplex_map::Simplex> Fake_simplex_tree::filtration_simplex_range(int d) const{
+ std::vector<Toplex_map::Simplex> m = max_simplices();
+ std::vector<Toplex_map::Simplex> range;
+ Toplex_map::Simplex_ptr_set seen;
+ while(m.begin()!=m.end()){
+ Toplex_map::Simplex s(m.back());
+ m.pop_back();
+ if(seen.find(get_key(s))==seen.end()){
+ if((int) s.size()-1 <=d)
+ range.emplace_back(s);
+ seen.emplace(get_key(s));
+ if(s.size()>0)
+ for(Simplex& sigma : facets(s))
+ m.emplace_back(sigma);
+ }
+ }
+ return range;
+}
+
+std::vector<Toplex_map::Simplex> Fake_simplex_tree::skeleton_simplex_range(int d) const{
+ return filtration_simplex_range(d);
+}
+
+Toplex_map::Vertex Fake_simplex_tree::contraction(const Toplex_map::Vertex x, const Toplex_map::Vertex y){
+ for(auto kv : toplex_maps)
+ kv.second->contraction(x,y);
+ return y;
+}
+
+} //namespace Gudhi
+
+#endif /* FAKE_SIMPLEX_TREE_H */
+
diff --git a/src/Toplex_map/example/Simple_toplex_map.cpp b/src/Toplex_map/example/Simple_toplex_map.cpp
new file mode 100644
index 00000000..d383e84b
--- /dev/null
+++ b/src/Toplex_map/example/Simple_toplex_map.cpp
@@ -0,0 +1,218 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Vincent Rouvreau
+ *
+ * Copyright (C) 2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gudhi/graph_simplicial_complex.h>
+#include "Fake_simplex_tree.h"
+
+#include <iostream>
+#include <utility> // for pair
+#include <vector>
+
+using Toplex_map = Gudhi::Fake_simplex_tree;
+using typeVectorVertex = std::vector< Toplex_map::Vertex_handle >;
+using typePairSimplexBool = std::pair< Toplex_map::Simplex_handle, bool >;
+
+int main(int argc, char * const argv[]) {
+
+ // TEST OF INSERTION
+ std::cout << "********************************************************************" << std::endl;
+ std::cout << "EXAMPLE OF SIMPLE INSERTION" << std::endl;
+ // Construct the Toplex_map
+ Toplex_map t_map;
+
+ /* Simplex to be inserted: */
+ /* 1 */
+ /* o */
+ /* /X\ */
+ /* o---o---o */
+ /* 2 0 3 */
+
+ // ++ FIRST
+ std::cout << " * INSERT 0" << std::endl;
+ typeVectorVertex firstSimplexVector = { 0 };
+ typePairSimplexBool returnValue = t_map.insert_simplex_and_subfaces(firstSimplexVector, 0.1);
+
+ if (returnValue.second == true) {
+ std::cout << " + 0 INSERTED" << std::endl;
+ } else {
+ std::cout << " - 0 NOT INSERTED" << std::endl;
+ }
+
+ // ++ SECOND
+ std::cout << " * INSERT 1" << std::endl;
+ typeVectorVertex secondSimplexVector = { 1 };
+ returnValue = t_map.insert_simplex_and_subfaces(secondSimplexVector, 0.1);
+
+ if (returnValue.second == true) {
+ std::cout << " + 1 INSERTED" << std::endl;
+ } else {
+ std::cout << " - 1 NOT INSERTED" << std::endl;
+ }
+
+ // ++ THIRD
+ std::cout << " * INSERT (0,1)" << std::endl;
+ typeVectorVertex thirdSimplexVector = { 0, 1 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(thirdSimplexVector, 0.2);
+
+ if (returnValue.second == true) {
+ std::cout << " + (0,1) INSERTED" << std::endl;
+ } else {
+ std::cout << " - (0,1) NOT INSERTED" << std::endl;
+ }
+
+ // ++ FOURTH
+ std::cout << " * INSERT 2" << std::endl;
+ typeVectorVertex fourthSimplexVector = { 2 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(fourthSimplexVector, 0.1);
+
+ if (returnValue.second == true) {
+ std::cout << " + 2 INSERTED" << std::endl;
+ } else {
+ std::cout << " - 2 NOT INSERTED" << std::endl;
+ }
+
+ // ++ FIFTH
+ std::cout << " * INSERT (2,0)" << std::endl;
+ typeVectorVertex fifthSimplexVector = { 2, 0 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(fifthSimplexVector, 0.2);
+
+ if (returnValue.second == true) {
+ std::cout << " + (2,0) INSERTED" << std::endl;
+ } else {
+ std::cout << " - (2,0) NOT INSERTED" << std::endl;
+ }
+
+ // ++ SIXTH
+ std::cout << " * INSERT (2,1)" << std::endl;
+ typeVectorVertex sixthSimplexVector = { 2, 1 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(sixthSimplexVector, 0.2);
+
+ if (returnValue.second == true) {
+ std::cout << " + (2,1) INSERTED" << std::endl;
+ } else {
+ std::cout << " - (2,1) NOT INSERTED" << std::endl;
+ }
+
+ // ++ SEVENTH
+ std::cout << " * INSERT (2,1,0)" << std::endl;
+ typeVectorVertex seventhSimplexVector = { 2, 1, 0 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(seventhSimplexVector, 0.3);
+
+ if (returnValue.second == true) {
+ std::cout << " + (2,1,0) INSERTED" << std::endl;
+ } else {
+ std::cout << " - (2,1,0) NOT INSERTED" << std::endl;
+ }
+
+ // ++ EIGHTH
+ std::cout << " * INSERT 3" << std::endl;
+ typeVectorVertex eighthSimplexVector = { 3 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(eighthSimplexVector, 0.1);
+
+ if (returnValue.second == true) {
+ std::cout << " + 3 INSERTED" << std::endl;
+ } else {
+ std::cout << " - 3 NOT INSERTED" << std::endl;
+ }
+
+ // ++ NINETH
+ std::cout << " * INSERT (3,0)" << std::endl;
+ typeVectorVertex ninethSimplexVector = { 3, 0 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(ninethSimplexVector, 0.2);
+
+ if (returnValue.second == true) {
+ std::cout << " + (3,0) INSERTED" << std::endl;
+ } else {
+ std::cout << " - (3,0) NOT INSERTED" << std::endl;
+ }
+
+ // ++ TENTH
+ std::cout << " * INSERT 0 (already inserted)" << std::endl;
+ typeVectorVertex tenthSimplexVector = { 0 };
+ // With a different filtration value
+ returnValue = t_map.insert_simplex_and_subfaces(tenthSimplexVector, 0.4);
+
+ if (returnValue.second == true) {
+ std::cout << " + 0 INSERTED" << std::endl;
+ } else {
+ std::cout << " - 0 NOT INSERTED" << std::endl;
+ }
+
+ // ++ ELEVENTH
+ std::cout << " * INSERT (2,1,0) (already inserted)" << std::endl;
+ typeVectorVertex eleventhSimplexVector = { 2, 1, 0 };
+ returnValue =
+ t_map.insert_simplex_and_subfaces(eleventhSimplexVector, 0.4);
+
+ if (returnValue.second == true) {
+ std::cout << " + (2,1,0) INSERTED" << std::endl;
+ } else {
+ std::cout << " - (2,1,0) NOT INSERTED" << std::endl;
+ }
+
+ // ++ GENERAL VARIABLE SET
+
+ std::cout << "********************************************************************\n";
+ // Display the Simplex_tree - Can not be done in the middle of 2 inserts
+ std::cout << "* The complex contains " << t_map.num_vertices() << " vertices and " << t_map.num_simplices()
+ << " simplices - dimension is " << t_map.dimension() << "\n";
+ std::cout << "* Iterator on Simplices in the filtration, with [filtration value]:\n";
+ for (auto f_simplex : t_map.filtration_simplex_range()) {
+ if (f_simplex.size() > 0) {
+ std::cout << " " << "[" << t_map.filtration(f_simplex) << "] ";
+ for (auto vertex : t_map.simplex_vertex_range(f_simplex))
+ std::cout << "(" << vertex << ")";
+ std::cout << std::endl;
+ }
+ }
+ // [0.1] 0
+ // [0.1] 1
+ // [0.1] 2
+ // [0.1] 3
+ // [0.2] 1 0
+ // [0.2] 2 0
+ // [0.2] 2 1
+ // [0.2] 3 0
+ // [0.3] 2 1 0
+
+ std::cout << std::endl << std::endl;
+
+ std::cout << "Iterator on skeleton[1]:" << std::endl;
+ for (auto f_simplex : t_map.skeleton_simplex_range(1)) {
+ if (f_simplex.size() > 0) {
+ std::cout << " " << "[" << t_map.filtration(f_simplex) << "] ";
+ for (auto vertex : t_map.simplex_vertex_range(f_simplex)) {
+ std::cout << vertex << " ";
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/Toplex_map/example/Toplex_map_from_cliques_of_graph.cpp b/src/Toplex_map/example/Toplex_map_from_cliques_of_graph.cpp
new file mode 100644
index 00000000..c43f1b69
--- /dev/null
+++ b/src/Toplex_map/example/Toplex_map_from_cliques_of_graph.cpp
@@ -0,0 +1,93 @@
+/* This file is part of the Gudhi Library. The Gudhi library
+ * (Geometric Understanding in Higher Dimensions) is a generic C++
+ * library for computational topology.
+ *
+ * Author(s): Vincent Rouvreau
+ *
+ * Copyright (C) 2017 INRIA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gudhi/reader_utils.h>
+#include "Fake_simplex_tree.h"
+
+#include <iostream>
+#include <ctime>
+#include <string>
+#include <utility> // for std::pair
+
+using Toplex_map = Gudhi::Fake_simplex_tree;
+using Vertex_handle = Toplex_map::Vertex_handle;
+using Filtration_value = Toplex_map::Filtration_value;
+
+typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS,
+ boost::property < vertex_filtration_t, Filtration_value >,
+ boost::property < edge_filtration_t, Filtration_value > > Graph_t;
+
+int main(int argc, char * const argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0]
+ << " path_to_file_graph max_dim \n";
+ return 0;
+ }
+ std::string filegraph = argv[1];
+ int max_dim = atoi(argv[2]);
+
+ clock_t start, end;
+ // Construct the Toplex Map
+ Toplex_map t_map;
+
+ start = clock();
+ auto g = Gudhi::read_graph<Graph_t, Filtration_value, Vertex_handle>(filegraph);
+ // insert the graph in the toplex map as 1-skeleton
+ t_map.insert_graph(g);
+ end = clock();
+ std::cout << "Insert the 1-skeleton in the toplex map in "
+ << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+
+ start = clock();
+ // expand the 1-skeleton until dimension max_dim
+ t_map.expansion(max_dim);
+ end = clock();
+ std::cout << "max_dim = " << max_dim << "\n";
+ std::cout << "Expand the toplex map in "
+ << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n";
+
+ std::cout << "Information of the toplex map: " << std::endl;
+ std::cout << " Number of vertices = " << t_map.num_vertices() << " ";
+ std::cout << " Number of simplices = " << t_map.num_simplices() << std::endl;
+ std::cout << std::endl << std::endl;
+
+ std::cout << "Iterator on Simplices in the filtration:" << std::endl;
+ for (auto f_simplex : t_map.filtration_simplex_range()) {
+ std::cout << " " << "[" << t_map.filtration(f_simplex) << "] ";
+ for (auto vertex : t_map.simplex_vertex_range(f_simplex)) {
+ std::cout << vertex << " ";
+ }
+ std::cout << std::endl;
+ }
+
+ std::cout << std::endl << std::endl;
+
+ std::cout << "Iterator on skeleton:" << std::endl;
+ for (auto f_simplex : t_map.skeleton_simplex_range(max_dim)) {
+ std::cout << " " << "[" << t_map.filtration(f_simplex) << "] ";
+ for (auto vertex : t_map.simplex_vertex_range(f_simplex)) {
+ std::cout << vertex << " ";
+ }
+ std::cout << std::endl;
+ }
+ return 0;
+}
diff --git a/src/Toplex_map/include/gudhi/Filtered_toplex_map.h b/src/Toplex_map/include/gudhi/Filtered_toplex_map.h
new file mode 100644
index 00000000..ed65e36f
--- /dev/null
+++ b/src/Toplex_map/include/gudhi/Filtered_toplex_map.h
@@ -0,0 +1,84 @@
+ #ifndef FILTERED_TOPLEX_MAP_H
+#define FILTERED_TOPLEX_MAP_H
+
+#include <gudhi/Toplex_map.h>
+#include <map>
+#include <limits>
+
+namespace Gudhi {
+
+/** A Filtered_toplex_map represents the simplicial complex with a filtration.
+ * A "toplex" is a critical simplex.
+ * \ingroup toplex_map */
+class Filtered_toplex_map {
+
+public:
+ /** Vertex is the type of vertices.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Vertex Vertex;
+
+ /** Simplex is the type of simplices.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex Simplex;
+
+ /** The type of the pointers to maximal simplices.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex_ptr Simplex_ptr;
+
+ /** The type of the sets of Simplex_ptr.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex_ptr_set Simplex_ptr_set;
+
+ /** The type of the filtration values.
+ * \ingroup toplex_map */
+ typedef double Filtration_value;
+
+ /** Add a simplex and its subfaces with the given filtration value
+ * in the Filtered_toplex_map.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ std::pair<Simplex, bool> insert_simplex_and_subfaces(const Input_vertex_range &vertex_range, Filtration_value f = std::numeric_limits<double>::quiet_NaN());
+
+ /** Gives the filtration of the input simplex.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ Filtration_value filtration(const Input_vertex_range &vertex_range) const;
+
+ /** Is the input simplex member of the complex ?
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool membership(const Input_vertex_range &vertex_range) const;
+
+protected:
+ std::map<Filtration_value, Toplex_map*> toplex_maps;
+};
+
+template <typename Input_vertex_range>
+std::pair<Toplex_map::Simplex, bool> Filtered_toplex_map::insert_simplex_and_subfaces(const Input_vertex_range &vertex_range, Filtration_value f){
+ Simplex s(vertex_range.begin(),vertex_range.end());
+ if(membership(s)) return make_pair(s,false);
+ if(!toplex_maps.count(f)) toplex_maps.emplace(f,new Toplex_map());
+ toplex_maps.at(f)->insert_simplex(vertex_range);
+ return make_pair(s,true);
+}
+
+
+template <typename Input_vertex_range>
+Filtered_toplex_map::Filtration_value Filtered_toplex_map::filtration(const Input_vertex_range &vertex_range) const{
+ for(auto kv : toplex_maps)
+ if(kv.second->membership(vertex_range))
+ return kv.first; //min only because a map is ordered
+ return std::numeric_limits<double>::quiet_NaN() ;
+}
+
+template <typename Input_vertex_range>
+bool Filtered_toplex_map::membership(const Input_vertex_range &vertex_range) const{
+ for(auto kv : toplex_maps)
+ if(kv.second->membership(vertex_range))
+ return true;
+ return false;
+}
+
+} //namespace Gudhi
+
+#endif /* FILTERED_TOPLEX_MAP_H */
diff --git a/src/Toplex_map/include/gudhi/Lazy_Toplex_map.h b/src/Toplex_map/include/gudhi/Lazy_Toplex_map.h
new file mode 100644
index 00000000..25281998
--- /dev/null
+++ b/src/Toplex_map/include/gudhi/Lazy_Toplex_map.h
@@ -0,0 +1,263 @@
+#ifndef LAZY_TOPLEX_MAP_H
+#define LAZY_TOPLEX_MAP_H
+
+#include <gudhi/Toplex_map.h>
+#include <boost/heap/fibonacci_heap.hpp>
+#include <cmath>
+
+namespace Gudhi {
+
+/** A Lazy_Toplex_map represents the simplicial complex.
+ * A "toplex" is a maximal simplex but not all simplices in a LTM are toplices.
+ * \ingroup toplex_map */
+class Lazy_Toplex_map {
+
+public:
+
+ /** Vertex is the type of vertices.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Vertex Vertex;
+
+ /** Simplex is the type of simplices.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex Simplex;
+
+ /** The type of the pointers to maximal simplices.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex_ptr Simplex_ptr;
+
+ /** The type of the sets of Simplex_ptr.
+ * \ingroup toplex_map */
+ typedef Toplex_map::Simplex_ptr_set Simplex_ptr_set;
+
+ /** Adds the given simplex to the complex.
+ * The simplex must not have maximal coface in the complex.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ void insert_independent_simplex(const Input_vertex_range &vertex_range);
+
+ /** \brief Adds the given simplex to the complex.
+ * Nothing happens if the simplex has a coface in the complex.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool insert_simplex(const Input_vertex_range &vertex_range);
+
+ /** \brief Removes the given simplex and its cofaces from the complex.
+ * Its faces are kept inside.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ void remove_simplex(const Input_vertex_range &vertex_range);
+
+ /** Does a simplex belong to the complex ?
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool membership(const Input_vertex_range &vertex_range);
+
+
+ /** Do all the facets of a simplex belong to the complex ?
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool all_facets_inside(const Input_vertex_range &vertex_range);
+
+ /** Contracts one edge in the complex.
+ * The edge has to verify the link condition if you want to preserve topology.
+ * Returns the remaining vertex.
+ * \ingroup toplex_map */
+ Vertex contraction(const Vertex x, const Vertex y);
+
+ /** \brief Number of simplices stored.
+ * \ingroup toplex_map */
+ std::size_t num_simplices() const;
+
+ std::unordered_map<Vertex, std::size_t> gamma0_lbounds;
+
+private:
+ template <typename Input_vertex_range>
+ void erase_max(const Input_vertex_range &vertex_range);
+ template <typename Input_vertex_range>
+ Vertex best_index(const Input_vertex_range &vertex_range);
+ void clean(const Vertex v);
+
+ std::unordered_map<Vertex, Simplex_ptr_set> t0;
+ bool empty_toplex; // Is the empty simplex a toplex ?
+
+ typedef boost::heap::fibonacci_heap<std::pair<std::size_t,Vertex>> PriorityQueue;
+ PriorityQueue cleaning_priority;
+ std::unordered_map<Vertex, PriorityQueue::handle_type> cp_handles;
+
+ std::size_t get_gamma0_lbound(const Vertex v) const;
+
+ std::size_t size_lbound = 0;
+ std::size_t size = 0;
+
+ const double alpha = 4; //time
+ const double betta = 8; //memory
+};
+
+template <typename Input_vertex_range>
+void Lazy_Toplex_map::insert_independent_simplex(const Input_vertex_range &vertex_range){
+ for(const Vertex& v : vertex_range)
+ if(!gamma0_lbounds.count(v)) gamma0_lbounds.emplace(v,1);
+ else gamma0_lbounds[v]++;
+ size_lbound++;
+ insert_simplex(vertex_range);
+}
+
+template <typename Input_vertex_range>
+bool Lazy_Toplex_map::insert_simplex(const Input_vertex_range &vertex_range){
+ Simplex sigma(vertex_range.begin(),vertex_range.end());
+ empty_toplex = (sigma.size()==0); //vérifier la gestion de empty face
+ Simplex_ptr sptr = std::make_shared<Simplex>(sigma);
+ bool inserted = false;
+ for(const Vertex& v : sigma){
+ if(!t0.count(v)){
+ t0.emplace(v, Simplex_ptr_set());
+ auto v_handle = cleaning_priority.push(std::make_pair(0, v));
+ cp_handles.emplace(v, v_handle);
+ }
+ inserted = t0.at(v).emplace(sptr).second;
+ cleaning_priority.update(cp_handles.at(v), std::make_pair(t0.at(v).size() - get_gamma0_lbound(v),v));
+ }
+ if(inserted)
+ size++;
+ if(size > (size_lbound+1) * betta)
+ clean(cleaning_priority.top().second);
+ return inserted;
+}
+
+template <typename Input_vertex_range>
+void Lazy_Toplex_map::remove_simplex(const Input_vertex_range &vertex_range){
+ if(vertex_range.begin()==vertex_range.end()){
+ t0.clear();
+ gamma0_lbounds.clear();
+ cleaning_priority.clear();
+ size_lbound = 0;
+ size = 0;
+ empty_toplex = false;
+ }
+ else {
+ const Vertex& v = best_index(vertex_range);
+ //Copy constructor needed because the set is modified
+ if(t0.count(v)) for(const Simplex_ptr& sptr : Simplex_ptr_set(t0.at(v)))
+ if(included(vertex_range, *sptr)){
+ erase_max(*sptr);
+ for(const Simplex& f : facets(vertex_range))
+ insert_independent_simplex(f);
+ }
+ }
+}
+
+template <typename Input_vertex_range>
+bool Lazy_Toplex_map::membership(const Input_vertex_range &vertex_range){
+ if(t0.size()==0 && !empty_toplex) return false; //empty complex
+ if(vertex_range.begin()==vertex_range.end()) return true; //empty query simplex
+ Vertex v = best_index(vertex_range);
+ if(!t0.count(v)) return false;
+ for(const Simplex_ptr& sptr : t0.at(v))
+ if(included(vertex_range, *sptr)) return true;
+ return false;
+}
+
+template <typename Input_vertex_range>
+bool Lazy_Toplex_map::all_facets_inside(const Input_vertex_range &vertex_range){
+ Simplex sigma(vertex_range.begin(),vertex_range.end());
+ Vertex v = best_index(sigma);
+ if(!t0.count(v)) return false;
+ Simplex f = sigma; f.erase(v);
+ if(!membership(f)) return false;
+ std::unordered_set<Vertex> facets_inside;
+ for(const Simplex_ptr& sptr : t0.at(v))
+ for(const Vertex& w : sigma){
+ f = sigma; f.erase(w);
+ if(included(f, *sptr)) facets_inside.insert(w);
+ }
+ return facets_inside.size() == sigma.size() - 1;
+}
+
+/* Returns the remaining vertex */
+Toplex_map::Vertex Lazy_Toplex_map::contraction(const Vertex x, const Vertex y){
+ if(!t0.count(x)) return y;
+ if(!t0.count(y)) return x;
+ Vertex k, d;
+ if(t0.at(x).size() > t0.at(y).size())
+ k=x, d=y;
+ else
+ k=y, d=x;
+ //Copy constructor needed because the set is modified
+ for(const Simplex_ptr& sptr : Simplex_ptr_set(t0.at(d))){
+ Simplex sigma(*sptr);
+ erase_max(sigma);
+ sigma.erase(d);
+ sigma.insert(k);
+ insert_simplex(sigma);
+ }
+ t0.erase(d);
+ return k;
+}
+
+/* No facets insert_simplexed */
+template <typename Input_vertex_range>
+inline void Lazy_Toplex_map::erase_max(const Input_vertex_range &vertex_range){
+ Simplex sigma(vertex_range.begin(),vertex_range.end());
+ empty_toplex = false;
+ Simplex_ptr sptr = std::make_shared<Simplex>(sigma);
+ bool erased=false;
+ for(const Vertex& v : sigma){
+ erased = t0.at(v).erase(sptr) > 0;
+ if(t0.at(v).size()==0)
+ t0.erase(v);
+ }
+ if (erased)
+ size--;
+}
+
+template <typename Input_vertex_range>
+Toplex_map::Vertex Lazy_Toplex_map::best_index(const Input_vertex_range &vertex_range){
+ Simplex tau(vertex_range.begin(),vertex_range.end());
+ std::size_t min = std::numeric_limits<size_t>::max(); Vertex arg_min = -1;
+ for(const Vertex& v : tau)
+ if(!t0.count(v)) return v;
+ else if(t0.at(v).size() < min)
+ min = t0.at(v).size(), arg_min = v;
+ if(min > alpha * get_gamma0_lbound(arg_min))
+ clean(arg_min);
+ return arg_min;
+}
+
+std::size_t Lazy_Toplex_map::get_gamma0_lbound(const Vertex v) const{
+ return gamma0_lbounds.count(v) ? gamma0_lbounds.at(v) : 0;
+}
+
+
+void Lazy_Toplex_map::clean(const Vertex v){
+ Toplex_map toplices;
+ std::unordered_map<int, std::vector<Simplex>> dsorted_simplices;
+ std::size_t max_dim = 0;
+ for(const Simplex_ptr& sptr : Simplex_ptr_set(t0.at(v))){
+ if(sptr->size() > max_dim){
+ for(std::size_t d = max_dim+1; d<=sptr->size(); d++)
+ dsorted_simplices.emplace(d, std::vector<Simplex>());
+ max_dim = sptr->size();
+ }
+ dsorted_simplices[sptr->size()].emplace_back(*sptr);
+ erase_max(*sptr);
+ }
+ for(std::size_t d = max_dim; d>=1; d--)
+ for(const Simplex &s : dsorted_simplices.at(d))
+ if(!toplices.membership(s))
+ toplices.insert_independent_simplex(s);
+ Simplex sv; sv.insert(v);
+ auto clean_cofaces = toplices.maximal_cofaces(sv);
+ size_lbound = size_lbound - get_gamma0_lbound(v) + clean_cofaces.size();
+ gamma0_lbounds[v] = clean_cofaces.size();
+ for(const Simplex_ptr& sptr : clean_cofaces)
+ insert_simplex(*sptr);
+}
+
+std::size_t Lazy_Toplex_map::num_simplices() const{
+ return size;
+}
+
+} //namespace Gudhi
+
+#endif /* LAZY_TOPLEX_MAP_H */
diff --git a/src/Toplex_map/include/gudhi/Toplex_map.h b/src/Toplex_map/include/gudhi/Toplex_map.h
new file mode 100644
index 00000000..73d2c63d
--- /dev/null
+++ b/src/Toplex_map/include/gudhi/Toplex_map.h
@@ -0,0 +1,322 @@
+#ifndef TOPLEX_MAP_H
+#define TOPLEX_MAP_H
+
+#include <vector>
+#include <set>
+#include <unordered_set>
+#include <unordered_map>
+#include <memory>
+#include <limits>
+
+#define vertex_upper_bound std::numeric_limits<Toplex_map::Vertex>::max()
+
+namespace Gudhi {
+
+/** A Toplex_map represents the simplicial complex.
+ * A "toplex" is a maximal simplex.
+ * \ingroup toplex_map */
+class Toplex_map {
+
+public:
+
+ /** Vertex is the type of vertices.
+ * \ingroup toplex_map */
+ typedef std::size_t Vertex;
+
+ /** Simplex is the type of simplices.
+ * \ingroup toplex_map */
+ typedef std::set<Toplex_map::Vertex> Simplex;
+
+ /** The type of the pointers to maximal simplices.
+ * \ingroup toplex_map */
+ typedef std::shared_ptr<Toplex_map::Simplex> Simplex_ptr;
+
+ struct Sptr_hash{ std::size_t operator()(const Toplex_map::Simplex_ptr& s) const; };
+ struct Sptr_equal{ std::size_t operator()(const Toplex_map::Simplex_ptr& a, const Toplex_map::Simplex_ptr& b) const; };
+ /** The type of the sets of Toplex_map::Simplex_ptr.
+ * \ingroup toplex_map */
+ typedef std::unordered_set<Toplex_map::Simplex_ptr, Sptr_hash, Sptr_equal> Simplex_ptr_set;
+
+ /** \brief Adds the given simplex to the complex.
+ * Nothing happens if the simplex has a coface in the complex.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ void insert_simplex(const Input_vertex_range &vertex_range);
+
+ /** \brief Removes the given simplex and its cofaces from the complex.
+ * Its faces are kept inside.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ void remove_simplex(const Input_vertex_range &vertex_range);
+
+ /** Does a simplex belong to the complex ?
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool membership(const Input_vertex_range &vertex_range) const;
+
+ /** Does a simplex is a toplex ?
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ bool maximality(const Input_vertex_range &vertex_range) const;
+
+ /** Gives a set of pointers to the maximal cofaces of a simplex.
+ * Gives all the toplices if given the empty simplex.
+ * Gives not more than max_number maximal cofaces if max_number is strictly positive.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ Toplex_map::Simplex_ptr_set maximal_cofaces(const Input_vertex_range &vertex_range, const std::size_t max_number = 0) const;
+
+ /** Contracts one edge in the complex.
+ * The edge has to verify the link condition if you want to preserve topology.
+ * Returns the remaining vertex.
+ * \ingroup toplex_map */
+ Toplex_map::Vertex contraction(const Toplex_map::Vertex x, const Toplex_map::Vertex y);
+
+ /** Adds the given simplex to the complex.
+ * The simplex must not have neither maximal face nor coface in the complex.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ void insert_independent_simplex(const Input_vertex_range &vertex_range);
+
+ /** \internal Removes a toplex without adding facets after.
+ * \ingroup toplex_map */
+ void erase_maximal(const Toplex_map::Simplex_ptr& sptr);
+
+ /** Removes a vertex from any simplex containing it.
+ * \ingroup toplex_map */
+ void remove_vertex(const Toplex_map::Vertex x);
+
+ /** \brief Number of maximal simplices.
+ * \ingroup toplex_map */
+ std::size_t num_simplices() const;
+
+ std::set<Toplex_map::Vertex> unitary_collapse(const Toplex_map::Vertex k, const Toplex_map::Vertex d);
+
+protected:
+ /** \internal Gives an index in order to look for a simplex quickly.
+ * \ingroup toplex_map */
+ template <typename Input_vertex_range>
+ Toplex_map::Vertex best_index(const Input_vertex_range &vertex_range) const;
+
+ /** \internal The map from vertices to toplices
+ * \ingroup toplex_map */
+ std::unordered_map<Toplex_map::Vertex, Toplex_map::Simplex_ptr_set> t0;
+};
+
+// Pointers are also used as key in the hash sets.
+template <typename Input_vertex_range>
+Toplex_map::Simplex_ptr get_key(const Input_vertex_range &vertex_range);
+
+// Is the first simplex a face of the second ?
+template <typename Input_vertex_range1, typename Input_vertex_range2>
+bool included(const Input_vertex_range1 &vertex_range1, const Input_vertex_range2 &vertex_range2);
+
+// All the facets of the given simplex.
+template <typename Input_vertex_range>
+std::vector<Toplex_map::Simplex> facets(const Input_vertex_range &vertex_range);
+
+template <typename Input_vertex_range>
+void Toplex_map::insert_simplex(const Input_vertex_range &vertex_range){
+ if(membership(vertex_range)) return;
+ bool replace_facets = true;
+ for(const Toplex_map::Simplex& facet : facets(vertex_range))
+ if(!maximality(facet))
+ {
+ replace_facets=false;
+ break;
+ }
+ if(replace_facets)
+ for(const Toplex_map::Simplex& facet : facets(vertex_range))
+ erase_maximal(get_key(facet));
+ else
+ for(const Toplex_map::Vertex& v : vertex_range)
+ if(t0.count(v)) for(const Toplex_map::Simplex_ptr& fptr : Simplex_ptr_set(t0.at(v)))
+ //Copy constructor needed because the set is modified
+ if(included(*fptr,vertex_range)) erase_maximal(fptr);
+ // We erase all the maximal faces of the simplex
+ insert_independent_simplex(vertex_range);
+}
+
+template <typename Input_vertex_range>
+void Toplex_map::remove_simplex(const Input_vertex_range &vertex_range){
+ if(vertex_range.begin()==vertex_range.end())
+ t0.clear();
+ // Removal of the empty simplex means cleaning everything
+ else {
+ const Toplex_map::Vertex& v = best_index(vertex_range);
+ if(t0.count(v)) for(const Toplex_map::Simplex_ptr& sptr : Simplex_ptr_set(t0.at(v)))
+ //Copy constructor needed because the set is modified
+ if(included(vertex_range, *sptr)){
+ erase_maximal(sptr);
+ for(const Toplex_map::Simplex& f : facets(vertex_range))
+ if(!membership(f)) insert_independent_simplex(f);
+ // We add the facets which are new maximal simplices
+ }
+ }
+}
+
+template <typename Input_vertex_range>
+bool Toplex_map::membership(const Input_vertex_range &vertex_range) const{
+ if(t0.size()==0) return false;
+ const Toplex_map::Vertex& v = best_index(vertex_range);
+ if(!t0.count(v)) return false;
+ if(maximality(vertex_range)) return true;
+ for(const Toplex_map::Simplex_ptr& sptr : t0.at(v))
+ if(included(vertex_range, *sptr))
+ return true;
+ return false;
+}
+
+template <typename Input_vertex_range>
+bool Toplex_map::maximality(const Input_vertex_range &vertex_range) const{
+ const Toplex_map::Vertex& v = best_index(vertex_range);
+ if(!t0.count(v)) return false;
+ return t0.at(v).count(get_key(vertex_range));
+}
+
+template <typename Input_vertex_range>
+Toplex_map::Simplex_ptr_set Toplex_map::maximal_cofaces(const Input_vertex_range &vertex_range, const std::size_t max_number) const{
+ Simplex_ptr_set cofaces;
+ if(maximality(vertex_range))
+ cofaces.emplace(get_key(vertex_range));
+ else if(vertex_range.begin()==vertex_range.end())
+ for(const auto& kv : t0)
+ for(const Toplex_map::Simplex_ptr& sptr : kv.second){
+ //kv.second is a Simplex_ptr_set
+ cofaces.emplace(sptr);
+ if(cofaces.size()==max_number)
+ return cofaces;
+ }
+ else {
+ const Toplex_map::Vertex& v = best_index(vertex_range);
+ if(t0.count(v)) for(const Toplex_map::Simplex_ptr& sptr : t0.at(v))
+ if(included(vertex_range, *sptr)){
+ cofaces.emplace(sptr);
+ if(cofaces.size()==max_number)
+ return cofaces;
+ }
+ }
+ return cofaces;
+}
+
+Toplex_map::Vertex Toplex_map::contraction(const Toplex_map::Vertex x, const Toplex_map::Vertex y){
+ if(!t0.count(x)) return y;
+ if(!t0.count(y)) return x;
+ int k, d;
+ if(t0.at(x).size() > t0.at(y).size())
+ k=x, d=y;
+ else
+ k=y, d=x;
+ for(const Toplex_map::Simplex_ptr& sptr : Simplex_ptr_set(t0.at(d))){
+ //Copy constructor needed because the set is modified
+ Simplex sigma(*sptr);
+ erase_maximal(sptr);
+ sigma.erase(d);
+ sigma.insert(k);
+ insert_simplex(sigma);
+ }
+ return k;
+}
+
+std::set<Toplex_map::Vertex> Toplex_map::unitary_collapse(const Toplex_map::Vertex k, const Toplex_map::Vertex d){
+ std::set<Toplex_map::Vertex> r;
+ for(const Toplex_map::Simplex_ptr& sptr : Simplex_ptr_set(t0.at(d))){
+ //Copy constructor needed because the set is modified
+ Simplex sigma(*sptr);
+ erase_maximal(sptr);
+ sigma.erase(d);
+ for(const Toplex_map::Vertex v : sigma)
+ r.insert(v);
+ sigma.insert(k);
+ insert_simplex(sigma);
+ }
+ return r;
+}
+
+template <typename Input_vertex_range>
+void Toplex_map::insert_independent_simplex(const Input_vertex_range &vertex_range){
+ auto key = get_key(vertex_range);
+ for(const Toplex_map::Vertex& v : vertex_range){
+ if(!t0.count(v)) t0.emplace(v, Simplex_ptr_set());
+ t0.at(v).emplace(key);
+ }
+}
+
+void Toplex_map::remove_vertex(const Toplex_map::Vertex x){
+ for(const Toplex_map::Simplex_ptr& sptr : Simplex_ptr_set(t0.at(x))){
+ Simplex sigma(*sptr);
+ erase_maximal(sptr);
+ sigma.erase(x);
+ insert_simplex(sigma);
+ }
+}
+
+std::size_t Toplex_map::num_simplices() const{
+ return maximal_cofaces(Simplex()).size();
+}
+
+inline void Toplex_map::erase_maximal(const Toplex_map::Simplex_ptr& sptr){
+ Simplex sigma(*sptr);
+ if (sptr->size()==0)
+ sigma.insert(vertex_upper_bound);
+ for(const Toplex_map::Vertex& v : sigma){
+ t0.at(v).erase(sptr);
+ if(t0.at(v).size()==0) t0.erase(v);
+ }
+}
+
+template <typename Input_vertex_range>
+Toplex_map::Vertex Toplex_map::best_index(const Input_vertex_range &vertex_range) const{
+ std::size_t min = std::numeric_limits<size_t>::max();
+ Vertex arg_min = vertex_upper_bound;
+ for(const Toplex_map::Vertex& v : vertex_range)
+ if(!t0.count(v)) return v;
+ else if(t0.at(v).size() < min)
+ min = t0.at(v).size(), arg_min = v;
+ return arg_min;
+}
+
+std::size_t Toplex_map::Sptr_equal::operator()(const Toplex_map::Simplex_ptr& s1, const Toplex_map::Simplex_ptr& s2) const {
+ if (s1->size() != s2->size()) return false;
+ return included(*s1,*s2);
+ // inclusion tests equality for same size simplices
+}
+
+std::size_t Toplex_map::Sptr_hash::operator()(const Toplex_map::Simplex_ptr& s) const {
+ std::hash<double> h_f;
+ //double hash works better than int hash
+ size_t h = 0;
+ for(const Toplex_map::Vertex& v : *s)
+ h += h_f(static_cast<double>(v));
+ return h;
+}
+
+template <typename Input_vertex_range>
+Toplex_map::Simplex_ptr get_key(const Input_vertex_range &vertex_range){
+ Toplex_map::Simplex s(vertex_range.begin(), vertex_range.end());
+ return std::make_shared<Toplex_map::Simplex>(s);
+}
+
+template <typename Input_vertex_range1, typename Input_vertex_range2>
+bool included(const Input_vertex_range1 &vertex_range1, const Input_vertex_range2 &vertex_range2){
+ Toplex_map::Simplex s2(vertex_range2.begin(), vertex_range2.end());
+ for(const Toplex_map::Vertex& v : vertex_range1)
+ if(!s2.count(v)) return false;
+ return true;
+}
+
+template <typename Input_vertex_range>
+std::vector<Toplex_map::Simplex> facets(const Input_vertex_range &vertex_range){
+ std::vector<Toplex_map::Simplex> facets;
+ Toplex_map::Simplex f(vertex_range.begin(), vertex_range.end());
+ for(const Toplex_map::Vertex& v : vertex_range){
+ f.erase(v);
+ facets.emplace_back(f);
+ f.insert(v);
+ }
+ return facets;
+}
+
+} //namespace Gudhi
+
+#endif /* TOPLEX_MAP_H */
diff --git a/src/Toplex_map/test/CMakeLists.txt b/src/Toplex_map/test/CMakeLists.txt
new file mode 100644
index 00000000..5ed55e97
--- /dev/null
+++ b/src/Toplex_map/test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.6)
+project(Toplex_map_tests)
+
+add_executable ( ToplexMapUT toplex_map_unit_test.cpp )
+target_link_libraries(ToplexMapUT ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+
+
+# Unitary tests
+add_test(NAME ToplexMapUT
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/ToplexMapUT
+ ${CMAKE_SOURCE_DIR}/src/Toplex_map/test/test.txt
+ # XML format for Jenkins xUnit plugin
+ --log_format=XML --log_sink=${CMAKE_SOURCE_DIR}/ToplexMapUT.xml --log_level=test_suite --report_level=no)
+
diff --git a/src/Toplex_map/test/toplex_map_unit_test.cpp b/src/Toplex_map/test/toplex_map_unit_test.cpp
new file mode 100644
index 00000000..c12ad094
--- /dev/null
+++ b/src/Toplex_map/test/toplex_map_unit_test.cpp
@@ -0,0 +1,54 @@
+#include <iostream>
+#include <gudhi/Filtered_toplex_map.h>
+
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "toplex map"
+#include <boost/test/unit_test.hpp>
+
+using namespace Gudhi;
+
+typedef Toplex_map::Vertex Vertex;
+
+std::vector<Vertex> sigma1 = {1, 2, 3, 4};
+std::vector<Vertex> sigma2 = {5, 2, 3, 6};
+std::vector<Vertex> sigma3 = {5};
+std::vector<Vertex> sigma4 = {5, 2, 3};
+std::vector<Vertex> sigma5 = {5, 2, 7};
+std::vector<Vertex> sigma6 = {4, 5, 3};
+std::vector<Vertex> sigma7 = {4, 5, 9};
+std::vector<Vertex> sigma8 = {1, 2, 3, 6};
+
+
+BOOST_AUTO_TEST_CASE(toplexmap) {
+ Toplex_map K;
+ K.insert_simplex(sigma1);
+ K.insert_simplex(sigma2);
+ K.insert_simplex(sigma3);
+ K.insert_simplex(sigma6);
+ K.insert_simplex(sigma7);
+ BOOST_CHECK(K.membership(sigma4));
+ BOOST_CHECK(!K.maximality(sigma3));
+ BOOST_CHECK(!K.membership(sigma5));
+ K.insert_simplex(sigma5);
+ std::vector<Vertex> sigma9 = {1, 2, 3};
+ std::vector<Vertex> sigma10 = {2, 7};
+ auto r = K.contraction(4,5);
+ sigma9.emplace_back(r);
+ sigma10.emplace_back(r);
+ BOOST_CHECK(!K.membership(sigma6));
+ BOOST_CHECK(K.membership(sigma9));
+ BOOST_CHECK(K.membership(sigma10));
+}
+
+
+BOOST_AUTO_TEST_CASE(ftoplexmap) {
+ Filtered_toplex_map K;
+ K.insert_simplex_and_subfaces(sigma1, 2.);
+ K.insert_simplex_and_subfaces(sigma2, 2.);
+ K.insert_simplex_and_subfaces(sigma6, 1.);
+ K.insert_simplex_and_subfaces(sigma7, 1.);
+ BOOST_CHECK(K.filtration(sigma4)==2.);
+ BOOST_CHECK(K.filtration(sigma3)==1.);
+}
+
diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h
index db1e80ce..5ccb648f 100644
--- a/src/common/doc/main_page.h
+++ b/src/common/doc/main_page.h
@@ -168,6 +168,23 @@
</td>
</tr>
</table>
+ \subsection ToplexMapDataStructure Toplex Map
+ \image html "map.png" "Toplex map representation"
+<table border="0">
+ <tr>
+ <td width="25%">
+ <b>Author:</b> Fran&ccedil;ois Godi<br>
+ <b>Introduced in:</b> GUDHI 2.1.0<br>
+ <b>Copyright:</b> GPL v3<br>
+ </td>
+ <td width="75%">
+ The Toplex map data structure is composed firstly of a raw storage of toplices (the maximal simplices)
+ and secondly of a map which associate any vertex to a set of pointers toward all toplices
+ containing this vertex.
+ <b>User manual:</b> \ref toplex_map - <b>Reference manual:</b> Gudhi::Toplex_map
+ </td>
+ </tr>
+
\subsection WitnessComplexDataStructure Witness complex
\image html "Witness_complex_representation.png" "Witness complex representation"
<table border="0">