diff options
Diffstat (limited to 'src/Simplex_tree')
17 files changed, 1444 insertions, 979 deletions
diff --git a/src/Simplex_tree/concept/IndexingTag.h b/src/Simplex_tree/concept/IndexingTag.h index d690da11..1dcdd756 100644 --- a/src/Simplex_tree/concept/IndexingTag.h +++ b/src/Simplex_tree/concept/IndexingTag.h @@ -25,6 +25,6 @@ * continuous maps to a cell complex, and compute its persistent * homology. * - * Must be linear_indexing_tag. + * Must be `Gudhi::linear_indexing_tag`. */ struct IndexingTag {}; diff --git a/src/Simplex_tree/concept/SimplexKey.h b/src/Simplex_tree/concept/SimplexKey.h index ce5b2382..7fdbdd84 100644 --- a/src/Simplex_tree/concept/SimplexKey.h +++ b/src/Simplex_tree/concept/SimplexKey.h @@ -22,7 +22,7 @@ /** \brief Key type used as simplex identifier. * - * Must be <CODE>int</CODE> + * Must be a signed integer type. */ struct SimplexKey {}; -
\ No newline at end of file + diff --git a/src/Simplex_tree/concept/SimplexTreeOptions.h b/src/Simplex_tree/concept/SimplexTreeOptions.h new file mode 100644 index 00000000..add3ebdd --- /dev/null +++ b/src/Simplex_tree/concept/SimplexTreeOptions.h @@ -0,0 +1,41 @@ + /* 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): Marc Glisse + * + * Copyright (C) 2015 INRIA Saclay - Ile-de-France (France) + * + * 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/>. + */ + +/** \brief Concept of the template parameter for the class `Gudhi::Simplex_tree<SimplexTreeOptions>`. + * + * One model for this is `Gudhi::Simplex_tree_options_full_featured`. If you want to provide your own, it is recommended that you derive from it and override some parts instead of writing a class from scratch. + */ +struct SimplexTreeOptions { + /// Forced for now. + typedef IndexingTag Indexing_tag; + /// Must be a signed integer type. It admits a total order <. + typedef VertexHandle Vertex_handle; + /// Must be comparable with operator<. + typedef FiltrationValue Filtration_value; + /// Must be a signed integer type. + typedef SimplexKey Simplex_key; + /// If true, each simplex has extra storage for one `Simplex_key`. Necessary for `Persistent_cohomology`. + static const bool store_key; + /// If true, each simplex has extra storage for one `Filtration_value`, and this value is propagated by operations like `Gudhi::Simplex_tree::expansion`. Without it, `Persistent_cohomology` degenerates to computing usual (non-persistent) cohomology. + static const bool store_filtration; +}; + diff --git a/src/Simplex_tree/concept/VertexHandle.h b/src/Simplex_tree/concept/VertexHandle.h index 491f0f56..3efbba61 100644 --- a/src/Simplex_tree/concept/VertexHandle.h +++ b/src/Simplex_tree/concept/VertexHandle.h @@ -22,5 +22,6 @@ /** \brief Handle type for the vertices of a cell complex. * - * Must be int.*/ + * Must be a signed integer type. <code>operator<</code> defines a total order on it. + */ struct VertexHandle {}; diff --git a/src/Simplex_tree/example/CMakeLists.txt b/src/Simplex_tree/example/CMakeLists.txt index 1a3cdfbf..c70cfe35 100644 --- a/src/Simplex_tree/example/CMakeLists.txt +++ b/src/Simplex_tree/example/CMakeLists.txt @@ -1,21 +1,24 @@ cmake_minimum_required(VERSION 2.6) project(GUDHISimplexTreeFromFile) -add_executable ( simplex_tree_from_file simplex_tree_from_file.cpp ) -add_test(simplex_tree_from_file_2 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_file ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 2) -add_test(simplex_tree_from_file_3 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_file ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 3) +add_executable ( simplex_tree_from_cliques_of_graph simplex_tree_from_cliques_of_graph.cpp ) +add_test(simplex_tree_from_cliques_of_graph_2 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_cliques_of_graph ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 2) +add_test(simplex_tree_from_cliques_of_graph_3 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_cliques_of_graph ${CMAKE_SOURCE_DIR}/data/points/Klein_bottle_complex.txt 3) add_executable ( simple_simplex_tree simple_simplex_tree.cpp ) add_test(simple_simplex_tree ${CMAKE_CURRENT_BINARY_DIR}/simple_simplex_tree) - + +add_executable ( mini_simplex_tree mini_simplex_tree.cpp ) +add_test(mini_simplex_tree ${CMAKE_CURRENT_BINARY_DIR}/mini_simplex_tree) + # An example with Simplex-tree using CGAL alpha_shapes_3 if(GMP_FOUND AND CGAL_FOUND) message("CGAL_lib = ${CGAL_LIBRARIES_DIR}") - message("GMP_LIBRARIES = ${GMP_LIBRARIES}") + message("GMP_LIBRARIES = ${GMP_LIBRARIES}") INCLUDE_DIRECTORIES(${GMP_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${CGAL_INCLUDE_DIRS}) add_executable ( simplex_tree_from_alpha_shapes_3 simplex_tree_from_alpha_shapes_3.cpp ) target_link_libraries(simplex_tree_from_alpha_shapes_3 ${GMP_LIBRARIES} ${CGAL_LIBRARY}) add_test(simplex_tree_from_alpha_shapes_3 ${CMAKE_CURRENT_BINARY_DIR}/simplex_tree_from_alpha_shapes_3 ${CMAKE_SOURCE_DIR}/data/points/bunny_5000) -endif() +endif() diff --git a/src/Simplex_tree/example/mini_simplex_tree.cpp b/src/Simplex_tree/example/mini_simplex_tree.cpp new file mode 100644 index 00000000..7e48aaaf --- /dev/null +++ b/src/Simplex_tree/example/mini_simplex_tree.cpp @@ -0,0 +1,69 @@ +/* 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): Marc Glisse + * + * Copyright (C) 2015 INRIA Saclay - Ile-de-France (France) + * + * 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/Simplex_tree.h> +#include <iostream> +#include <initializer_list> + +using namespace Gudhi; + +struct MyOptions : Simplex_tree_options_full_featured { + // Not doing persistence, so we don't need those + static const bool store_key = false; + static const bool store_filtration = false; + // I have few vertices + typedef short Vertex_handle; +}; +typedef Simplex_tree<MyOptions> ST; + +// Dictionary should be private, but for now this is the easiest way. +static_assert(sizeof(ST::Dictionary::value_type) < sizeof(Simplex_tree<>::Dictionary::value_type), + "Not storing the filtration and key should save some space"); + +int main() { + ST st; + + /* Complex to build. */ + /* 1 */ + /* o */ + /* /X\ */ + /* o---o---o */ + /* 2 0 3 */ + + auto triangle012 = {0, 1, 2}; + auto edge03 = {0, 3}; + st.insert_simplex_and_subfaces(triangle012); + st.insert_simplex_and_subfaces(edge03); + // FIXME: Remove this line + st.set_dimension(2); + + auto edge02 = {0, 2}; + ST::Simplex_handle e = st.find(edge02); + // We are not using filtrations so everything has value 0 + assert(st.filtration(e) == 0); + for (ST::Simplex_handle t : st.cofaces_simplex_range(e, 1)) { + // Only coface is 012 + for (ST::Vertex_handle v : st.simplex_vertex_range(t)) // v in { 0, 1, 2 } + std::cout << v; + std::cout << '\n'; + } +} diff --git a/src/Simplex_tree/example/simple_simplex_tree.cpp b/src/Simplex_tree/example/simple_simplex_tree.cpp index 6d20e43e..5146b906 100644 --- a/src/Simplex_tree/example/simple_simplex_tree.cpp +++ b/src/Simplex_tree/example/simple_simplex_tree.cpp @@ -20,10 +20,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <gudhi/graph_simplicial_complex.h> +#include <gudhi/Simplex_tree.h> + #include <iostream> -#include <ctime> -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" +#include <utility> // for pair +#include <vector> using namespace Gudhi; @@ -35,15 +37,11 @@ int main(int argc, char * const argv[]) { const Filtration_value SECOND_FILTRATION_VALUE = 0.2; const Filtration_value THIRD_FILTRATION_VALUE = 0.3; const Filtration_value FOURTH_FILTRATION_VALUE = 0.4; - Vertex_handle FIRST_VERTEX_HANDLE = (Vertex_handle) 0; - Vertex_handle SECOND_VERTEX_HANDLE = (Vertex_handle) 1; - Vertex_handle THIRD_VERTEX_HANDLE = (Vertex_handle) 2; - Vertex_handle FOURTH_VERTEX_HANDLE = (Vertex_handle) 3; // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; std::cout << "EXAMPLE OF SIMPLE INSERTION" << std::endl; - //Construct the Simplex Tree + // Construct the Simplex Tree Simplex_tree<> simplexTree; /* Simplex to be inserted: */ @@ -55,190 +53,149 @@ int main(int argc, char * const argv[]) { // ++ FIRST std::cout << " * INSERT 0" << std::endl; - typeVectorVertex firstSimplexVector; - firstSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex firstSimplexVector = { 0 }; typePairSimplexBool returnValue = simplexTree.insert_simplex(firstSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 0 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 0 NOT INSERTED" << std::endl; } // ++ SECOND std::cout << " * INSERT 1" << std::endl; - typeVectorVertex secondSimplexVector; - secondSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex secondSimplexVector = { 1 }; returnValue = simplexTree.insert_simplex(secondSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 1 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 1 NOT INSERTED" << std::endl; } // ++ THIRD std::cout << " * INSERT (0,1)" << std::endl; - typeVectorVertex thirdSimplexVector; - thirdSimplexVector.push_back(FIRST_VERTEX_HANDLE); - thirdSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex thirdSimplexVector = { 0, 1 }; returnValue = simplexTree.insert_simplex(thirdSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (0,1) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (0,1) NOT INSERTED" << std::endl; } // ++ FOURTH std::cout << " * INSERT 2" << std::endl; - typeVectorVertex fourthSimplexVector; - fourthSimplexVector.push_back(THIRD_VERTEX_HANDLE); + typeVectorVertex fourthSimplexVector = { 2 }; returnValue = simplexTree.insert_simplex(fourthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 2 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 2 NOT INSERTED" << std::endl; } // ++ FIFTH std::cout << " * INSERT (2,0)" << std::endl; - typeVectorVertex fifthSimplexVector; - fifthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - fifthSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex fifthSimplexVector = { 2, 0 }; returnValue = simplexTree.insert_simplex(fifthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,0) NOT INSERTED" << std::endl; } // ++ SIXTH std::cout << " * INSERT (2,1)" << std::endl; - typeVectorVertex sixthSimplexVector; - sixthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - sixthSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex sixthSimplexVector = { 2, 1 }; returnValue = simplexTree.insert_simplex(sixthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,1) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,1) NOT INSERTED" << std::endl; } // ++ SEVENTH std::cout << " * INSERT (2,1,0)" << std::endl; - typeVectorVertex seventhSimplexVector; - seventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - seventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - seventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex seventhSimplexVector = { 2, 1, 0 }; returnValue = simplexTree.insert_simplex(seventhSimplexVector, Filtration_value(THIRD_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,1,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,1,0) NOT INSERTED" << std::endl; } // ++ EIGHTH std::cout << " * INSERT 3" << std::endl; - typeVectorVertex eighthSimplexVector; - eighthSimplexVector.push_back(FOURTH_VERTEX_HANDLE); + typeVectorVertex eighthSimplexVector = { 3 }; returnValue = simplexTree.insert_simplex(eighthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 3 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 3 NOT INSERTED" << std::endl; } // ++ NINETH std::cout << " * INSERT (3,0)" << std::endl; - typeVectorVertex ninethSimplexVector; - ninethSimplexVector.push_back(FOURTH_VERTEX_HANDLE); - ninethSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex ninethSimplexVector = { 3, 0 }; returnValue = simplexTree.insert_simplex(ninethSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (3,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (3,0) NOT INSERTED" << std::endl; } // ++ TENTH std::cout << " * INSERT 0 (already inserted)" << std::endl; - typeVectorVertex tenthSimplexVector; - tenthSimplexVector.push_back(FIRST_VERTEX_HANDLE); - returnValue = - simplexTree.insert_simplex(tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); // With a different filtration value + typeVectorVertex tenthSimplexVector = { 0 }; + // With a different filtration value + returnValue = simplexTree.insert_simplex(tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + 0 INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - 0 NOT INSERTED" << std::endl; } // ++ ELEVENTH std::cout << " * INSERT (2,1,0) (already inserted)" << std::endl; - typeVectorVertex eleventhSimplexVector; - eleventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - eleventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - eleventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex eleventhSimplexVector = { 2, 1, 0 }; returnValue = simplexTree.insert_simplex(eleventhSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); if (returnValue.second == true) { std::cout << " + (2,1,0) INSERTED" << std::endl; - int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); } else { std::cout << " - (2,1,0) NOT INSERTED" << std::endl; } // ++ GENERAL VARIABLE SET - simplexTree.set_filtration(FOURTH_FILTRATION_VALUE); // Max filtration value - simplexTree.set_dimension(2); // Max dimension = 2 -> (2,1,0) + simplexTree.set_filtration(FOURTH_FILTRATION_VALUE); // Max filtration value + simplexTree.set_dimension(2); // Max dimension = 2 -> (2,1,0) - std::cout << "********************************************************************" << std::endl; + std::cout << "********************************************************************\n"; // Display the Simplex_tree - Can not be done in the middle of 2 inserts - std::cout << "* The complex contains " << simplexTree.num_simplices() << " simplices" << std::endl; - std::cout << " - dimension " << simplexTree.dimension() << " - filtration " << simplexTree.filtration() << std::endl; - std::cout << "* Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + std::cout << "* The complex contains " << simplexTree.num_simplices() << " simplices\n"; + std::cout << " - dimension " << simplexTree.dimension() << " - filtration " << simplexTree.filtration() << "\n"; + std::cout << "* Iterator on Simplices in the filtration, with [filtration value]:\n"; for (auto f_simplex : simplexTree.filtration_simplex_range()) { std::cout << " " << "[" << simplexTree.filtration(f_simplex) << "] "; for (auto vertex : simplexTree.simplex_vertex_range(f_simplex)) { - std::cout << (int) vertex << " "; + std::cout << static_cast<int>(vertex) << " "; } std::cout << std::endl; } @@ -262,9 +219,7 @@ int main(int argc, char * const argv[]) { else std::cout << "***- NO IT ISN'T\n"; - Vertex_handle UNKNOWN_VERTEX_HANDLE = (Vertex_handle) 15; - typeVectorVertex unknownSimplexVector; - unknownSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); + typeVectorVertex unknownSimplexVector = { 15 }; simplexFound = simplexTree.find(unknownSimplexVector); std::cout << "**************IS THE SIMPLEX {15} IN THE SIMPLEX TREE ?\n"; if (simplexFound != simplexTree.null_simplex()) @@ -279,9 +234,7 @@ int main(int argc, char * const argv[]) { else std::cout << "***- NO IT ISN'T\n"; - typeVectorVertex otherSimplexVector; - otherSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); - otherSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex otherSimplexVector = { 1, 15 }; simplexFound = simplexTree.find(otherSimplexVector); std::cout << "**************IS THE SIMPLEX {15,1} IN THE SIMPLEX TREE ?\n"; if (simplexFound != simplexTree.null_simplex()) @@ -289,10 +242,7 @@ int main(int argc, char * const argv[]) { else std::cout << "***- NO IT ISN'T\n"; - typeVectorVertex invSimplexVector; - invSimplexVector.push_back(SECOND_VERTEX_HANDLE); - invSimplexVector.push_back(THIRD_VERTEX_HANDLE); - invSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex invSimplexVector = { 1, 2, 0 }; simplexFound = simplexTree.find(invSimplexVector); std::cout << "**************IS THE SIMPLEX {1,2,0} IN THE SIMPLEX TREE ?\n"; if (simplexFound != simplexTree.null_simplex()) diff --git a/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp b/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp index 5f797e93..45efe3ed 100644 --- a/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp +++ b/src/Simplex_tree/example/simplex_tree_from_alpha_shapes_3.cpp @@ -1,24 +1,28 @@ - /* 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) 2014 INRIA Saclay (France) - * - * 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/>. - */ +/* 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) 2014 INRIA Saclay (France) + * + * 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 <gudhi/Simplex_tree.h> +#include <boost/variant.hpp> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Delaunay_triangulation_3.h> @@ -27,32 +31,34 @@ #include <fstream> #include <cmath> - -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/Simplex_tree.h" -#include <boost/variant.hpp> +#include <string> +#include <tuple> // for tuple<> +#include <map> +#include <utility> // for pair<> +#include <list> +#include <vector> // Alpha_shape_3 templates type definitions typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Alpha_shape_vertex_base_3<Kernel> Vb; -typedef CGAL::Alpha_shape_cell_base_3<Kernel> Fb; -typedef CGAL::Triangulation_data_structure_3<Vb,Fb> Tds; -typedef CGAL::Delaunay_triangulation_3<Kernel,Tds> Triangulation_3; -typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3; +typedef CGAL::Alpha_shape_vertex_base_3<Kernel> Vb; +typedef CGAL::Alpha_shape_cell_base_3<Kernel> Fb; +typedef CGAL::Triangulation_data_structure_3<Vb, Fb> Tds; +typedef CGAL::Delaunay_triangulation_3<Kernel, Tds> Triangulation_3; +typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3; // From file type definition -typedef Kernel::Point_3 Point; +typedef Kernel::Point_3 Point; // filtration with alpha values needed type definition typedef Alpha_shape_3::FT Alpha_value_type; -typedef CGAL::Object Object; +typedef CGAL::Object Object; typedef CGAL::Dispatch_output_iterator< - CGAL::cpp11::tuple<Object, Alpha_value_type>, - CGAL::cpp11::tuple<std::back_insert_iterator< std::vector<Object> >, std::back_insert_iterator< std::vector<Alpha_value_type> > - > > Dispatch; -typedef Alpha_shape_3::Cell_handle Cell_handle; -typedef Alpha_shape_3::Facet Facet; -typedef Alpha_shape_3::Edge Edge; +CGAL::cpp11::tuple<Object, Alpha_value_type>, +CGAL::cpp11::tuple<std::back_insert_iterator< std::vector<Object> >, + std::back_insert_iterator< std::vector<Alpha_value_type> > > > Dispatch; +typedef Alpha_shape_3::Cell_handle Cell_handle; +typedef Alpha_shape_3::Facet Facet; +typedef Alpha_shape_3::Edge Edge; typedef std::list<Alpha_shape_3::Vertex_handle> Vertex_list; // gudhi type definition @@ -61,225 +67,209 @@ typedef std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex > Alpha_shape typedef std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex> Alpha_shape_simplex_tree_pair; typedef std::vector< Simplex_tree_vertex > Simplex_tree_vector_vertex; -//#define DEBUG_TRACES - -Vertex_list from (const Cell_handle& ch) -{ - Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { +Vertex_list from(const Cell_handle& ch) { + Vertex_list the_list; + for (auto i = 0; i < 4; i++) { #ifdef DEBUG_TRACES - std::cout << "from cell[" << i << "]=" << ch->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(ch->vertex(i)); - } - return the_list; + std::cout << "from cell[" << i << "]=" << ch->vertex(i)->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(ch->vertex(i)); + } + return the_list; } -Vertex_list from (const Facet& fct) -{ - Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { - if (fct.second != i) - { + +Vertex_list from(const Facet& fct) { + Vertex_list the_list; + for (auto i = 0; i < 4; i++) { + if (fct.second != i) { #ifdef DEBUG_TRACES - std::cout << "from facet=[" << i << "]" << fct.first->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(fct.first->vertex(i)); - } - } - return the_list; + std::cout << "from facet=[" << i << "]" << fct.first->vertex(i)->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(fct.first->vertex(i)); + } + } + return the_list; } -Vertex_list from (const Edge& edg) -{ - Vertex_list the_list; - for (auto i = 0; i < 4; i++) - { - if ((edg.second == i) ||(edg.third == i)) - { + +Vertex_list from(const Edge& edg) { + Vertex_list the_list; + for (auto i = 0; i < 4; i++) { + if ((edg.second == i) || (edg.third == i)) { #ifdef DEBUG_TRACES - std::cout << "from edge[" << i << "]=" << edg.first->vertex(i)->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(edg.first->vertex(i)); - } - } - return the_list; + std::cout << "from edge[" << i << "]=" << edg.first->vertex(i)->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(edg.first->vertex(i)); + } + } + return the_list; } -Vertex_list from (const Alpha_shape_3::Vertex_handle& vh) -{ - Vertex_list the_list; + +Vertex_list from(const Alpha_shape_3::Vertex_handle& vh) { + Vertex_list the_list; #ifdef DEBUG_TRACES - std::cout << "from vertex=" << vh->point() << std::endl; -#endif // DEBUG_TRACES - the_list.push_back(vh); - return the_list; + std::cout << "from vertex=" << vh->point() << std::endl; +#endif // DEBUG_TRACES + the_list.push_back(vh); + return the_list; } +int main(int argc, char * const argv[]) { + // program args management + if (argc != 2) { + std::cerr << "Usage: " << argv[0] + << " path_to_file_graph \n"; + return 0; + } -int main (int argc, char * const argv[]) -{ - // program args management - if (argc != 2) { - std::cerr << "Usage: " << argv[0] - << " path_to_file_graph \n"; - return 0; // ----- >> - } - - // Read points from file - std::string filegraph = argv[1]; - std::list<Point> lp; - std::ifstream is(filegraph.c_str()); - int n; - is >> n; + // Read points from file + std::string filegraph = argv[1]; + std::list<Point> lp; + std::ifstream is(filegraph.c_str()); + int n; + is >> n; #ifdef DEBUG_TRACES - std::cout << "Reading " << n << " points " << std::endl; -#endif // DEBUG_TRACES - Point p; - for( ; n>0 ; n--) { - is >> p; - lp.push_back(p); - } + std::cout << "Reading " << n << " points " << std::endl; +#endif // DEBUG_TRACES + Point p; + for (; n > 0; n--) { + is >> p; + lp.push_back(p); + } - // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. - Alpha_shape_3 as(lp.begin(),lp.end(),0,Alpha_shape_3::GENERAL); + // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. + Alpha_shape_3 as(lp.begin(), lp.end(), 0, Alpha_shape_3::GENERAL); #ifdef DEBUG_TRACES - std::cout << "Alpha shape computed in GENERAL mode" << std::endl; -#endif // DEBUG_TRACES + std::cout << "Alpha shape computed in GENERAL mode" << std::endl; +#endif // DEBUG_TRACES - // filtration with alpha values from alpha shape - std::vector<Object> the_objects; - std::vector<Alpha_value_type> the_alpha_values; + // filtration with alpha values from alpha shape + std::vector<Object> the_objects; + std::vector<Alpha_value_type> the_alpha_values; - Dispatch disp = CGAL::dispatch_output<Object, Alpha_value_type>( std::back_inserter(the_objects), std::back_inserter(the_alpha_values)); + Dispatch disp = CGAL::dispatch_output<Object, Alpha_value_type>(std::back_inserter(the_objects), + std::back_inserter(the_alpha_values)); - as.filtration_with_alpha_values(disp); + as.filtration_with_alpha_values(disp); #ifdef DEBUG_TRACES - std::cout << "filtration_with_alpha_values returns : " << the_objects.size() << " objects" << std::endl; -#endif // DEBUG_TRACES + std::cout << "filtration_with_alpha_values returns : " << the_objects.size() << " objects" << std::endl; +#endif // DEBUG_TRACES - Alpha_shape_3::size_type count_vertices = 0; - Alpha_shape_3::size_type count_edges = 0; - Alpha_shape_3::size_type count_facets = 0; - Alpha_shape_3::size_type count_cells = 0; + Alpha_shape_3::size_type count_vertices = 0; + Alpha_shape_3::size_type count_edges = 0; + Alpha_shape_3::size_type count_facets = 0; + Alpha_shape_3::size_type count_cells = 0; - // Loop on objects vector - Vertex_list vertex_list; - Gudhi::Simplex_tree<> simplex_tree; - Alpha_shape_simplex_tree_map map_cgal_simplex_tree; - std::vector<Alpha_value_type>::iterator the_alpha_value_iterator = the_alpha_values.begin(); - for(auto object_iterator: the_objects) - { - // Retrieve Alpha shape vertex list from object - if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) - { - vertex_list = from(*cell); - count_cells++; - } - else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) - { - vertex_list = from(*facet); - count_facets++; - } - else if (const Edge* edge = CGAL::object_cast<Edge>(&object_iterator)) - { - vertex_list = from(*edge); - count_edges++; - } - else if (const Alpha_shape_3::Vertex_handle* vertex = CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) - { - count_vertices++; - vertex_list = from(*vertex); - } - // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex - Simplex_tree_vector_vertex the_simplex_tree; - for (auto the_alpha_shape_vertex:vertex_list) - { - Alpha_shape_simplex_tree_map::iterator the_map_iterator = map_cgal_simplex_tree.find(the_alpha_shape_vertex); - if (the_map_iterator == map_cgal_simplex_tree.end()) - { - // alpha shape not found - Simplex_tree_vertex vertex = map_cgal_simplex_tree.size(); + // Loop on objects vector + Vertex_list vertex_list; + Gudhi::Simplex_tree<> simplex_tree; + Alpha_shape_simplex_tree_map map_cgal_simplex_tree; + std::vector<Alpha_value_type>::iterator the_alpha_value_iterator = the_alpha_values.begin(); + for (auto object_iterator : the_objects) { + // Retrieve Alpha shape vertex list from object + if (const Cell_handle * cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { + vertex_list = from(*cell); + count_cells++; + } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { + vertex_list = from(*facet); + count_facets++; + } else if (const Edge * edge = CGAL::object_cast<Edge>(&object_iterator)) { + vertex_list = from(*edge); + count_edges++; + } else if (const Alpha_shape_3::Vertex_handle * vertex = + CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) { + count_vertices++; + vertex_list = from(*vertex); + } + // Construction of the vector of simplex_tree vertex from list of alpha_shapes vertex + Simplex_tree_vector_vertex the_simplex_tree; + for (auto the_alpha_shape_vertex : vertex_list) { + Alpha_shape_simplex_tree_map::iterator the_map_iterator = map_cgal_simplex_tree.find(the_alpha_shape_vertex); + if (the_map_iterator == map_cgal_simplex_tree.end()) { + // alpha shape not found + Simplex_tree_vertex vertex = map_cgal_simplex_tree.size(); #ifdef DEBUG_TRACES - std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] not found - insert_simplex " << vertex << std::endl; -#endif // DEBUG_TRACES - the_simplex_tree.push_back(vertex); - map_cgal_simplex_tree.insert(Alpha_shape_simplex_tree_pair(the_alpha_shape_vertex,vertex)); - } else - { - // alpha shape found - Simplex_tree_vertex vertex = the_map_iterator->second; + std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] not found - insert_simplex " << vertex << "\n"; +#endif // DEBUG_TRACES + the_simplex_tree.push_back(vertex); + map_cgal_simplex_tree.insert(Alpha_shape_simplex_tree_pair(the_alpha_shape_vertex, vertex)); + } else { + // alpha shape found + Simplex_tree_vertex vertex = the_map_iterator->second; #ifdef DEBUG_TRACES - std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] found in " << vertex << std::endl; -#endif // DEBUG_TRACES - the_simplex_tree.push_back(vertex); - } - } - // Construction of the simplex_tree + std::cout << "vertex [" << the_alpha_shape_vertex->point() << "] found in " << vertex << std::endl; +#endif // DEBUG_TRACES + the_simplex_tree.push_back(vertex); + } + } + // Construction of the simplex_tree #ifdef DEBUG_TRACES - std::cout << "filtration = " << *the_alpha_value_iterator << std::endl; -#endif // DEBUG_TRACES - simplex_tree.insert_simplex(the_simplex_tree, std::sqrt(*the_alpha_value_iterator)); - if (the_alpha_value_iterator != the_alpha_values.end()) - ++the_alpha_value_iterator; - else - std::cout << "This shall not happen" << std::endl; - } + std::cout << "filtration = " << *the_alpha_value_iterator << std::endl; +#endif // DEBUG_TRACES + simplex_tree.insert_simplex(the_simplex_tree, std::sqrt(*the_alpha_value_iterator)); + if (the_alpha_value_iterator != the_alpha_values.end()) + ++the_alpha_value_iterator; + else + std::cerr << "This shall not happen" << std::endl; + } #ifdef DEBUG_TRACES - std::cout << "vertices \t\t" << count_vertices << std::endl; - std::cout << "edges \t\t" << count_edges << std::endl; - std::cout << "facets \t\t" << count_facets << std::endl; - std::cout << "cells \t\t" << count_cells << std::endl; + std::cout << "vertices \t\t" << count_vertices << std::endl; + std::cout << "edges \t\t" << count_edges << std::endl; + std::cout << "facets \t\t" << count_facets << std::endl; + std::cout << "cells \t\t" << count_cells << std::endl; - std::cout << "Information of the Simplex Tree: " << std::endl; - std::cout << " Number of vertices = " << simplex_tree.num_vertices() << " "; - std::cout << " Number of simplices = " << simplex_tree.num_simplices() << std::endl << std::endl; -#endif // DEBUG_TRACES + std::cout << "Information of the Simplex Tree:\n"; + std::cout << " Number of vertices = " << simplex_tree.num_vertices() << " "; + std::cout << " Number of simplices = " << simplex_tree.num_simplices() << std::endl << std::endl; +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES - std::cout << "Iterator on vertices: " << std::endl; - for( auto vertex : simplex_tree.complex_vertex_range() ) - { std::cout << vertex << " "; } -#endif // DEBUG_TRACES + std::cout << "Iterator on vertices: \n"; + for (auto vertex : simplex_tree.complex_vertex_range()) { + std::cout << vertex << " "; + } +#endif // DEBUG_TRACES - std::cout << simplex_tree << std::endl; + std::cout << simplex_tree << std::endl; #ifdef DEBUG_TRACES - std::cout << std::endl << std::endl << "Iterator on simplices: " << std::endl; - for( auto simplex : simplex_tree.complex_simplex_range() ) - { - std::cout << " "; - for( auto vertex : simplex_tree.simplex_vertex_range(simplex) ) { std::cout << vertex << " "; } - std::cout << std::endl; - } -#endif // DEBUG_TRACES + std::cout << std::endl << std::endl << "Iterator on simplices:\n"; + for (auto simplex : simplex_tree.complex_simplex_range()) { + std::cout << " "; + for (auto vertex : simplex_tree.simplex_vertex_range(simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : simplex_tree.filtration_simplex_range() ) - { std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; - } -#endif // DEBUG_TRACES + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:\n"; + for (auto f_simplex : simplex_tree.filtration_simplex_range()) { + std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; + for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } +#endif // DEBUG_TRACES #ifdef DEBUG_TRACES - std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, and their boundary simplices:" << std::endl; - for( auto f_simplex : simplex_tree.filtration_simplex_range() ) - { - std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, and their boundary simplices:\n"; + for (auto f_simplex : simplex_tree.filtration_simplex_range()) { + std::cout << " " << "[" << simplex_tree.filtration(f_simplex) << "] "; + for (auto vertex : simplex_tree.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; - for( auto b_simplex : simplex_tree.boundary_simplex_range(f_simplex) ) - { - std::cout << " " << "[" << simplex_tree.filtration(b_simplex) << "] "; - for( auto vertex : simplex_tree.simplex_vertex_range(b_simplex) ) - { std::cout << vertex << " "; } - std::cout << std::endl; - } - } -#endif // DEBUG_TRACES + for (auto b_simplex : simplex_tree.boundary_simplex_range(f_simplex)) { + std::cout << " " << "[" << simplex_tree.filtration(b_simplex) << "] "; + for (auto vertex : simplex_tree.simplex_vertex_range(b_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + } +#endif // DEBUG_TRACES - return 0; + return 0; } diff --git a/src/Simplex_tree/example/simplex_tree_from_cliques_of_graph.cpp b/src/Simplex_tree/example/simplex_tree_from_cliques_of_graph.cpp new file mode 100644 index 00000000..58085014 --- /dev/null +++ b/src/Simplex_tree/example/simplex_tree_from_cliques_of_graph.cpp @@ -0,0 +1,114 @@ +/* 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): Clément Maria + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) + * + * 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 <gudhi/Simplex_tree.h> + +#include <iostream> +#include <ctime> +#include <string> + +using namespace Gudhi; + +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 Simplex Tree + Simplex_tree<> st; + + start = clock(); + auto g = read_graph(filegraph); + // insert the graph in the simplex tree as 1-skeleton + st.insert_graph(g); + end = clock(); + std::cout << "Insert the 1-skeleton in the simplex tree in " + << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n"; + + start = clock(); + // expand the 1-skeleton until dimension max_dim + st.expansion(max_dim); + end = clock(); + std::cout << "max_dim = " << max_dim << "\n"; + std::cout << "Expand the simplex tree in " + << static_cast<double>(end - start) / CLOCKS_PER_SEC << " s. \n"; + + std::cout << "Information of the Simplex Tree: " << std::endl; + std::cout << " Number of vertices = " << st.num_vertices() << " "; + std::cout << " Number of simplices = " << st.num_simplices() << std::endl; + std::cout << std::endl << std::endl; + + std::cout << "Iterator on vertices: "; + for (auto vertex : st.complex_vertex_range()) { + std::cout << vertex << " "; + } + + std::cout << std::endl; + + std::cout << std::endl << std::endl; + + std::cout << "Iterator on simplices: " << std::endl; + for (auto simplex : st.complex_simplex_range()) { + std::cout << " "; + for (auto vertex : st.simplex_vertex_range(simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + + std::cout << std::endl << std::endl; + + std::cout << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + for (auto f_simplex : st.filtration_simplex_range()) { + std::cout << " " << "[" << st.filtration(f_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + + std::cout << std::endl << std::endl; + + std::cout << "Iterator on Simplices in the filtration, and their boundary simplices:" << std::endl; + for (auto f_simplex : st.filtration_simplex_range()) { + std::cout << " " << "[" << st.filtration(f_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + + for (auto b_simplex : st.boundary_simplex_range(f_simplex)) { + std::cout << " " << "[" << st.filtration(b_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(b_simplex)) { + std::cout << vertex << " "; + } + std::cout << std::endl; + } + } + return 0; +} diff --git a/src/Simplex_tree/example/simplex_tree_from_file.cpp b/src/Simplex_tree/example/simplex_tree_from_file.cpp deleted file mode 100644 index 20e8f067..00000000 --- a/src/Simplex_tree/example/simplex_tree_from_file.cpp +++ /dev/null @@ -1,104 +0,0 @@ - /* 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): Clément Maria - * - * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (France) - * - * 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 <iostream> -#include <ctime> -#include "gudhi/reader_utils.h" -#include "gudhi/Simplex_tree.h" - -using namespace Gudhi; - -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 Simplex Tree - Simplex_tree<> st; - - start = clock(); - auto g = read_graph(filegraph); - st.insert_graph (g); //insert the graph in the simplex tree as 1-skeleton - end = clock(); - std::cout << "Insert the 1-skeleton in the simplex tree in " - << (double)(end-start)/CLOCKS_PER_SEC << " s. \n"; - - start = clock(); - st.expansion ( max_dim ); //expand the 1-skeleton until dimension max_dim - end = clock(); - std::cout << "max_dim = " << max_dim << "\n"; - std::cout << "Expand the simplex tree in " - << (double)(end-start)/CLOCKS_PER_SEC << " s. \n"; - - std::cout << "Information of the Simplex Tree: " << std::endl; - std::cout << " Number of vertices = " << st.num_vertices() << " "; - std::cout << " Number of simplices = " << st.num_simplices() << std::endl; - std::cout << std::endl << std::endl; - - std::cout << "Iterator on vertices: "; - for( auto vertex : st.complex_vertex_range() ) { std::cout << vertex << " "; } - - std::cout << std::endl; - - std::cout << std::endl << std::endl; - - std::cout << "Iterator on simplices: " << std::endl; - for( auto simplex : st.complex_simplex_range() ) - { - std::cout << " "; - for( auto vertex : st.simplex_vertex_range(simplex) ) { std::cout << vertex << " "; } - std::cout << std::endl; - } - - std::cout << std::endl << std::endl; - - std::cout << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } std::cout << std::endl; - } - - std::cout << std::endl << std::endl; - - std::cout << "Iterator on Simplices in the filtration, and their boundary simplices:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { - std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { std::cout << vertex << " "; } std::cout << std::endl; - - for( auto b_simplex : st.boundary_simplex_range(f_simplex) ) - { - std::cout << " " << "[" << st.filtration(b_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(b_simplex) ) - { std::cout << vertex << " "; } std::cout << std::endl; - } - } - return 0; -} diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree.h b/src/Simplex_tree/include/gudhi/Simplex_tree.h index 5d3753ca..ea61fa2e 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -20,14 +20,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_H_ +#ifndef SIMPLEX_TREE_H_ +#define SIMPLEX_TREE_H_ #include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h> #include <gudhi/Simplex_tree/Simplex_tree_siblings.h> #include <gudhi/Simplex_tree/Simplex_tree_iterators.h> #include <gudhi/Simplex_tree/indexing_tag.h> +#include <gudhi/reader_utils.h> +#include <gudhi/graph_simplicial_complex.h> + #include <boost/container/flat_map.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/graph/adjacency_list.hpp> @@ -35,10 +38,11 @@ #include <algorithm> #include <utility> #include <vector> -#include <iostream> +#include <functional> // for greater<> +#include <initializer_list> namespace Gudhi { - + /** \defgroup simplex_tree Filtered Complexes * * A simplicial complex \f$\mathbf{K}\f$ @@ -73,6 +77,17 @@ namespace Gudhi { * \copyright GNU General Public License v3. * @{ */ + +/// Model of SimplexTreeOptions. +struct Simplex_tree_options_full_featured { + typedef linear_indexing_tag Indexing_tag; + typedef int Vertex_handle; + typedef double Filtration_value; + typedef int Simplex_key; + static const bool store_key = true; + static const bool store_filtration = true; +}; + /** * \brief Simplex Tree data structure for representing simplicial complexes. * @@ -84,46 +99,69 @@ namespace Gudhi { * \implements FilteredComplex * */ -template<typename IndexingTag = linear_indexing_tag, - typename FiltrationValue = double, typename SimplexKey = int // must be a signed integer type - , typename VertexHandle = int // must be a signed integer type, int convertible to it -// , bool ContiguousVertexHandles = true //true is Vertex_handles are exactly the set [0;n) -> + +template<typename SimplexTreeOptions = Simplex_tree_options_full_featured> class Simplex_tree { public: - typedef IndexingTag Indexing_tag; + typedef SimplexTreeOptions Options; + typedef typename Options::Indexing_tag Indexing_tag; /** \brief Type for the value of the filtration function. * * Must be comparable with <. */ - typedef FiltrationValue Filtration_value; + typedef typename Options::Filtration_value Filtration_value; /** \brief Key associated to each simplex. * * Must be a signed integer type. */ - typedef SimplexKey Simplex_key; + typedef typename Options::Simplex_key Simplex_key; /** \brief Type for the vertex handle. * * Must be a signed integer type. It admits a total order <. */ - typedef VertexHandle Vertex_handle; + typedef typename Options::Vertex_handle Vertex_handle; /* Type of node in the simplex tree. */ typedef Simplex_tree_node_explicit_storage<Simplex_tree> Node; /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */ + // Note: this wastes space when Vertex_handle is 32 bits and Node is aligned on 64 bits. It would be better to use a + // flat_set (with our own comparator) where we can control the layout of the struct (put Vertex_handle and + // Simplex_key next to each other). typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary; - friend class Simplex_tree_node_explicit_storage< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_siblings< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle>, Dictionary>; - friend class Simplex_tree_simplex_vertex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_boundary_simplex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_complex_simplex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - friend class Simplex_tree_skeleton_simplex_iterator< Simplex_tree<FiltrationValue, SimplexKey, VertexHandle> >; - /* \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; + struct Key_simplex_base_real { + Key_simplex_base_real() : key_(-1) {} + void assign_key(Simplex_key k) { key_ = k; } + Simplex_key key() const { return key_; } + private: + Simplex_key key_; + }; + struct Key_simplex_base_dummy { + Key_simplex_base_dummy() {} + void assign_key(Simplex_key) { } + Simplex_key key() const { assert(false); return -1; } + }; + typedef typename std::conditional<Options::store_key, Key_simplex_base_real, Key_simplex_base_dummy>::type Key_simplex_base; + + struct Filtration_simplex_base_real { + Filtration_simplex_base_real() : filt_(0) {} + void assign_filtration(Filtration_value f) { filt_ = f; } + Filtration_value filtration() const { return filt_; } + private: + Filtration_value filt_; + }; + struct Filtration_simplex_base_dummy { + Filtration_simplex_base_dummy() {} + void assign_filtration(Filtration_value f) { assert(f == 0); } + Filtration_value filtration() const { return 0; } + }; + typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real, + Filtration_simplex_base_dummy>::type Filtration_simplex_base; + public: /** \brief Handle type to a simplex contained in the simplicial complex represented - * byt he simplex tree. */ + * by the simplex tree. */ typedef typename Dictionary::iterator Simplex_handle; private: @@ -157,6 +195,8 @@ class Simplex_tree { typedef Simplex_tree_simplex_vertex_iterator<Simplex_tree> Simplex_vertex_iterator; /** \brief Range over the vertices of a simplex. */ typedef boost::iterator_range<Simplex_vertex_iterator> Simplex_vertex_range; + /** \brief Range over the cofaces of a simplex. */ + typedef std::vector<Simplex_handle> Cofaces_simplex_range; /** \brief Iterator over the simplices of the boundary of a simplex. * * 'value_type' is Simplex_handle. */ @@ -177,24 +217,23 @@ class Simplex_tree { /** \brief Range over the simplices of the skeleton of the simplicial complex, for a given * dimension. */ typedef boost::iterator_range<Skeleton_simplex_iterator> Skeleton_simplex_range; + /** \brief Range over the simplices of the simplicial complex, ordered by the filtration. */ + typedef std::vector<Simplex_handle> Filtration_simplex_range; /** \brief Iterator over the simplices of the simplicial complex, ordered by the filtration. * * 'value_type' is Simplex_handle. */ - typedef typename std::vector<Simplex_handle>::iterator Filtration_simplex_iterator; - /** \brief Range over the simplices of the simplicial complex, ordered by the filtration. */ - typedef boost::iterator_range<Filtration_simplex_iterator> Filtration_simplex_range; + typedef typename Filtration_simplex_range::const_iterator Filtration_simplex_iterator; /* @} */ // end name range and iterator types /** \name Range and iterator methods * @{ */ - /** \brief Returns a range over the vertices of the simplicial complex. - * + /** \brief Returns a range over the vertices of the simplicial complex. * The order is increasing according to < on Vertex_handles.*/ Complex_vertex_range complex_vertex_range() { return Complex_vertex_range( - boost::make_transform_iterator(root_.members_.begin(), return_first()), - boost::make_transform_iterator(root_.members_.end(), return_first())); + boost::make_transform_iterator(root_.members_.begin(), return_first()), + boost::make_transform_iterator(root_.members_.end(), return_first())); } /** \brief Returns a range over the simplices of the simplicial complex. @@ -234,18 +273,15 @@ class Simplex_tree { * order is used. * * The filtration must be valid. If the filtration has not been initialized yet, the - * method initializes it (i.e. order the simplices). */ - Filtration_simplex_range filtration_simplex_range(Indexing_tag) { + * method initializes it (i.e. order the simplices). If the complex has changed since the last time the filtration + * was initialized, please call `initialize_filtration()` to recompute it. */ + Filtration_simplex_range const& filtration_simplex_range(Indexing_tag = Indexing_tag()) { if (filtration_vect_.empty()) { initialize_filtration(); } - return Filtration_simplex_range(filtration_vect_.begin(), - filtration_vect_.end()); + return filtration_vect_; } - Filtration_simplex_range filtration_simplex_range() { - return filtration_simplex_range(Indexing_tag()); - } /** \brief Returns a range over the vertices of a simplex. * * The order in which the vertices are visited is the decreasing order for < on Vertex_handles, @@ -253,6 +289,7 @@ class Simplex_tree { * equal to \f$(-1)^{\text{dim} \sigma}\f$ the canonical orientation on the simplex. */ Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) { + assert(sh != null_simplex()); // Empty simplex return Simplex_vertex_range(Simplex_vertex_iterator(this, sh), Simplex_vertex_iterator(this)); } @@ -283,11 +320,48 @@ class Simplex_tree { /** \brief Constructs an empty simplex tree. */ Simplex_tree() : null_vertex_(-1), - threshold_(0), - num_simplices_(0), - root_(NULL, null_vertex_), - filtration_vect_(), - dimension_(-1) { + threshold_(0), + root_(nullptr, null_vertex_), + filtration_vect_(), + dimension_(-1) { } + + /** \brief User-defined copy constructor reproduces the whole tree structure. */ + Simplex_tree(const Simplex_tree& simplex_source) + : null_vertex_(simplex_source.null_vertex_), + threshold_(simplex_source.threshold_), + filtration_vect_(), + dimension_(simplex_source.dimension_) { + auto root_source = simplex_source.root_; + auto memb_source = root_source.members(); + root_ = Siblings(nullptr, null_vertex_, memb_source); + rec_copy(&root_, &root_source); + } + + /** \brief depth first search, inserts simplices when reaching a leaf. */ + void rec_copy(Siblings *sib, Siblings *sib_source) { + for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin(); + sh != sib->members().end(); ++sh, ++sh_source) { + if (has_children(sh_source)) { + Siblings * newsib = new Siblings(sib, sh_source->first); + newsib->members_.reserve(sh_source->second.children()->members().size()); + for (auto & child : sh_source->second.children()->members()) + newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(sib, child.second.filtration())); + rec_copy(newsib, sh_source->second.children()); + sh->second.assign_children(newsib); + } + } + } + + /** \brief User-defined move constructor moves the whole tree structure. */ + Simplex_tree(Simplex_tree && old) + : null_vertex_(std::move(old.null_vertex_)), + threshold_(std::move(old.threshold_)), + root_(std::move(old.root_)), + filtration_vect_(std::move(old.filtration_vect_)), + dimension_(std::move(old.dimension_)) { + old.dimension_ = -1; + old.threshold_ = 0; + old.root_ = Siblings(nullptr, null_vertex_); } /** \brief Destructor; deallocates the whole tree structure. */ @@ -300,7 +374,7 @@ class Simplex_tree { } /** @} */ // end constructor/destructor private: - /** Recursive deletion. */ + // Recursive deletion void rec_delete(Siblings * sib) { for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) { if (has_children(sh)) { @@ -311,72 +385,135 @@ class Simplex_tree { } public: + /** \brief Checks if two simplex trees are equal. */ + bool operator==(Simplex_tree& st2) { + if ((null_vertex_ != st2.null_vertex_) || + (threshold_ != st2.threshold_) || + (dimension_ != st2.dimension_)) + return false; + return rec_equal(&root_, &st2.root_); + } + + /** \brief Checks if two simplex trees are different. */ + bool operator!=(Simplex_tree& st2) { + return (!(*this == st2)); + } + + private: + /** rec_equal: Checks recursively whether or not two simplex trees are equal, using depth first search. */ + bool rec_equal(Siblings* s1, Siblings* s2) { + if (s1->members().size() != s2->members().size()) + return false; + for (auto sh1 = s1->members().begin(), sh2 = s2->members().begin(); + (sh1 != s1->members().end() && sh2 != s2->members().end()); ++sh1, ++sh2) { + if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration()) + return false; + if (has_children(sh1) != has_children(sh2)) + return false; + // Recursivity on children only if both have children + else if (has_children(sh1)) + if (!rec_equal(sh1->second.children(), sh2->second.children())) + return false; + } + return true; + } + + public: /** \brief Returns the key associated to a simplex. * - * The filtration must be initialized. */ - Simplex_key key(Simplex_handle sh) { + * The filtration must be initialized. + * \pre SimplexTreeOptions::store_key + */ + static Simplex_key key(Simplex_handle sh) { return sh->second.key(); } + /** \brief Returns the simplex associated to a key. * - * The filtration must be initialized. */ - Simplex_handle simplex(Simplex_key key) { + * The filtration must be initialized. + * \pre SimplexTreeOptions::store_key + */ + Simplex_handle simplex(Simplex_key key) const { return filtration_vect_[key]; } + /** \brief Returns the filtration value of a simplex. * - * Called on the null_simplex, returns INFINITY. */ - Filtration_value filtration(Simplex_handle sh) const { + * Called on the null_simplex, returns INFINITY. + * If SimplexTreeOptions::store_filtration is false, returns 0. + */ + static Filtration_value filtration(Simplex_handle sh) { if (sh != null_simplex()) { return sh->second.filtration(); } else { return INFINITY; - } // filtration(); } + } } + /** \brief Returns an upper bound of the filtration values of the simplices. */ Filtration_value filtration() const { return threshold_; } + /** \brief Returns a Simplex_handle different from all Simplex_handles * associated to the simplices in the simplicial complex. * * One can call filtration(null_simplex()). */ - Simplex_handle null_simplex() const { - return Dictionary_it(NULL); + static Simplex_handle null_simplex() { + return Dictionary_it(nullptr); } + /** \brief Returns a key different for all keys associated to the * simplices of the simplicial complex. */ - Simplex_key null_key() const { + static Simplex_key null_key() { return -1; } + /** \brief Returns a Vertex_handle different from all Vertex_handles associated * to the vertices of the simplicial complex. */ Vertex_handle null_vertex() const { return null_vertex_; } + /** \brief Returns the number of vertices in the complex. */ size_t num_vertices() const { return root_.members_.size(); } - /** \brief Returns the number of simplices in the complex. - * - * Does not count the empty simplex. */ - unsigned int num_simplices() const { - return num_simplices_; + + public: + /** \brief returns the number of simplices in the simplex_tree. */ + size_t num_simplices() { + return num_simplices(&root_); } + private: + /** \brief returns the number of simplices in the simplex_tree. */ + size_t num_simplices(Siblings * sib) { + auto sib_begin = sib->members().begin(); + auto sib_end = sib->members().end(); + size_t simplices_number = sib_end - sib_begin; + for (auto sh = sib_begin; sh != sib_end; ++sh) { + if (has_children(sh)) { + simplices_number += num_simplices(sh->second.children()); + } + } + return simplices_number; + } + + public: /** \brief Returns the dimension of a simplex. * * Must be different from null_simplex().*/ int dimension(Simplex_handle sh) { Siblings * curr_sib = self_siblings(sh); int dim = 0; - while (curr_sib != NULL) { + while (curr_sib != nullptr) { ++dim; curr_sib = curr_sib->oncles(); } return dim - 1; } + /** \brief Returns an upper bound on the dimension of the simplicial complex. */ int dimension() const { return dimension_; @@ -388,25 +525,34 @@ class Simplex_tree { return (sh->second.children()->parent() == sh->first); } - /** \brief Given a range of Vertex_handles, returns the Simplex_handle + /** \brief Given a range of Vertex_handles, returns the Simplex_handle * of the simplex in the simplicial complex containing the corresponding * vertices. Return null_simplex() if the simplex is not in the complex. * - * The type RandomAccessVertexRange must be a range for which .begin() and - * .end() return random access iterators, with <CODE>value_type</CODE> - * <CODE>Vertex_handle</CODE>. + * The type InputVertexRange must be a range of <CODE>Vertex_handle</CODE> + * on which we can call std::begin() function */ - template<class RandomAccessVertexRange> - Simplex_handle find(RandomAccessVertexRange & s) { - if (s.begin() == s.end()) - std::cerr << "Empty simplex \n"; - - sort(s.begin(), s.end()); + template<class InputVertexRange=std::initializer_list<Vertex_handle>> + Simplex_handle find(const InputVertexRange & s) { + auto first = std::begin(s); + auto last = std::end(s); + + if (first == last) + return null_simplex(); // ----->> + + // Copy before sorting + std::vector<Vertex_handle> copy(first, last); + std::sort(std::begin(copy), std::end(copy)); + return find_simplex(copy); + } + private: + /** Find function, with a sorted range of vertices. */ + Simplex_handle find_simplex(const std::vector<Vertex_handle> & simplex) { Siblings * tmp_sib = &root_; Dictionary_it tmp_dit; - Vertex_handle last = s[s.size() - 1]; - for (auto v : s) { + Vertex_handle last = simplex.back(); + for (auto v : simplex) { tmp_dit = tmp_sib->members_.find(v); if (tmp_dit == tmp_sib->members_.end()) { return null_simplex(); @@ -424,8 +570,39 @@ class Simplex_tree { Simplex_handle find_vertex(Vertex_handle v) { return root_.members_.begin() + v; } -//{ return root_.members_.find(v); } + //{ return root_.members_.find(v); } + + private: + /** \brief Inserts a simplex represented by a vector of vertex. + \warning the vector must be sorted by increasing vertex handle order */ + std::pair<Simplex_handle, bool> insert_vertex_vector(const std::vector<Vertex_handle>& 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) { + res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); + if (!(has_children(res_insert.first))) { + res_insert.first->second.assign_children(new Siblings(curr_sib, *vi)); + } + curr_sib = res_insert.first->second.children(); + } + res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); + if (!res_insert.second) { + // if already in the complex + if (res_insert.first->second.filtration() > filtration) { + // if filtration value modified + res_insert.first->second.assign_filtration(filtration); + return res_insert; + } + // if filtration value unchanged + return std::pair<Simplex_handle, bool>(null_simplex(), false); + } + // otherwise the insertion has succeeded + return res_insert; + } + public: /** \brief Insert a simplex, represented by a range of Vertex_handles, in the simplicial complex. * * @param[in] simplex range of Vertex_handles, representing the vertices of the new simplex @@ -435,7 +612,7 @@ class Simplex_tree { * to the new simplex. * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration', - * we assign this simplex with the new value 'filtration', and set the Simplex_handle filed of the + * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to * null_simplex. * @@ -447,76 +624,107 @@ class Simplex_tree { * The filtration value * assigned to the new simplex must preserve the monotonicity of the filtration. * - * The type RandomAccessVertexRange must be a range for which .begin() and - * .end() return random access iterators, with 'value_type' Vertex_handle. */ - template<class RandomAccessVertexRange> - std::pair<Simplex_handle, bool> insert_simplex(RandomAccessVertexRange & simplex, - Filtration_value filtration) { - if (simplex.empty()) { - return std::pair<Simplex_handle, bool>(null_simplex(), true); - } - - sort(simplex.begin(), simplex.end()); // must be sorted in increasing order - - Siblings * curr_sib = &root_; - std::pair<Simplex_handle, bool> res_insert; - typename RandomAccessVertexRange::iterator vi; - for (vi = simplex.begin(); vi != simplex.end() - 1; ++vi) { - res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); - if (!(has_children(res_insert.first))) { - res_insert.first->second.assign_children(new Siblings(curr_sib, *vi)); - } - curr_sib = res_insert.first->second.children(); - } - res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration)); - if (!res_insert.second) { // if already in the complex - if (res_insert.first->second.filtration() > filtration) { // if filtration value modified - res_insert.first->second.assign_filtration(filtration); - return res_insert; - } - return std::pair<Simplex_handle, bool>(null_simplex(), false); // if filtration value unchanged - } - // otherwise the insertion has succeeded - return res_insert; + * The type InputVertexRange must be a range for which .begin() and + * .end() return input iterators, with 'value_type' Vertex_handle. */ + template<class InputVertexRange=std::initializer_list<Vertex_handle>> + std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex, + Filtration_value filtration = 0) { + auto first = std::begin(simplex); + auto last = std::end(simplex); + + if (first == last) + return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->> + + // Copy before sorting + std::vector<Vertex_handle> copy(first, last); + std::sort(std::begin(copy), std::end(copy)); + return insert_vertex_vector(copy, filtration); } - - /** \brief Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of + /** \brief Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of * Vertex_handles, in the simplicial complex. * * @param[in] Nsimplex range of Vertex_handles, representing the vertices of the new N-simplex * @param[in] filtration the filtration value assigned to the new N-simplex. - */ - template<class RandomAccessVertexRange> - void insert_simplex_and_subfaces(RandomAccessVertexRange& Nsimplex, - Filtration_value filtration = 0.0) { - if (Nsimplex.size() > 1) { - for (unsigned int NIndex = 0; NIndex < Nsimplex.size(); NIndex++) { - // insert N (N-1)-Simplex - RandomAccessVertexRange NsimplexMinusOne; - for (unsigned int NListIter = 0; NListIter < Nsimplex.size() - 1; NListIter++) { - // (N-1)-Simplex creation - NsimplexMinusOne.push_back( Nsimplex[(NIndex + NListIter) % Nsimplex.size()]); - } - // (N-1)-Simplex recursive call - insert_simplex_and_subfaces(NsimplexMinusOne, filtration); + * The return type is a pair. 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 + * to the new simplex. + * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion + * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration', + * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the + * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to + * null_simplex. + */ + template<class InputVertexRange=std::initializer_list<Vertex_handle>> + std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex, + Filtration_value filtration = 0) { + auto first = std::begin(Nsimplex); + auto last = std::end(Nsimplex); + + if (first == last) + return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->> + + // Copy before sorting + std::vector<Vertex_handle> copy(first, last); + std::sort(std::begin(copy), std::end(copy)); + + std::vector<std::vector<Vertex_handle>> to_be_inserted; + std::vector<std::vector<Vertex_handle>> to_be_propagated; + return rec_insert_simplex_and_subfaces(copy, to_be_inserted, to_be_propagated, filtration); + } + + private: + std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces(std::vector<Vertex_handle>& the_simplex, + std::vector<std::vector<Vertex_handle>>& to_be_inserted, + std::vector<std::vector<Vertex_handle>>& to_be_propagated, + Filtration_value filtration = 0.0) { + std::pair<Simplex_handle, bool> insert_result; + if (the_simplex.size() > 1) { + // Get and remove last vertex + Vertex_handle last_vertex = the_simplex.back(); + the_simplex.pop_back(); + // Recursive call after last vertex removal + insert_result = rec_insert_simplex_and_subfaces(the_simplex, to_be_inserted, to_be_propagated, filtration); + + // Concatenation of to_be_inserted and to_be_propagated + to_be_inserted.insert(to_be_inserted.begin(), to_be_propagated.begin(), to_be_propagated.end()); + to_be_propagated = to_be_inserted; + + // to_be_inserted treatment + for (auto& simplex_tbi : to_be_inserted) { + simplex_tbi.push_back(last_vertex); } - // N-Simplex insert - std::pair<Simplex_handle, bool> returned = insert_simplex(Nsimplex, filtration); - if (returned.second == true) { - num_simplices_++; + std::vector<Vertex_handle> last_simplex(1, last_vertex); + to_be_inserted.insert(to_be_inserted.begin(), last_simplex); + // i.e. (0,1,2) => + // [to_be_inserted | to_be_propagated] = [(1) (0,1) | (0)] + // [to_be_inserted | to_be_propagated] = [(2) (0,2) (1,2) (0,1,2) | (0) (1) (0,1)] + // N.B. : it is important the last inserted to be the highest in dimension + // in order to return the "last" insert_simplex result + + // insert all to_be_inserted + for (auto& simplex_tbi : to_be_inserted) { + insert_result = insert_vertex_vector(simplex_tbi, filtration); } - } else if (Nsimplex.size() == 1) { - // 1-Simplex insert - End of recursivity - std::pair<Simplex_handle, bool> returned = insert_simplex(Nsimplex, filtration); - if (returned.second == true) { - num_simplices_++; + } else if (the_simplex.size() == 1) { + // When reaching the end of recursivity, vector of simplices shall be empty and filled on back recursive + if ((to_be_inserted.size() != 0) || (to_be_propagated.size() != 0)) { + std::cerr << "Simplex_tree::rec_insert_simplex_and_subfaces - Error vector not empty" << std::endl; + exit(-1); } + std::vector<Vertex_handle> first_simplex(1, the_simplex.back()); + // i.e. (0,1,2) => [to_be_inserted | to_be_propagated] = [(0) | ] + to_be_inserted.push_back(first_simplex); + + insert_result = insert_vertex_vector(first_simplex, filtration); } else { - // Nothing to insert - empty vector + std::cerr << "Simplex_tree::rec_insert_simplex_and_subfaces - Recursivity error" << std::endl; + exit(-1); } + return insert_result; } + public: /** \brief Assign a value 'key' to the key of the simplex * represented by the Simplex_handle 'sh'. */ void assign_key(Simplex_handle sh, Simplex_key key) { @@ -528,9 +736,8 @@ class Simplex_tree { * and edge. sh must point to a 1-dimensional simplex. This is an * optimized version of the boundary computation. */ std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) { - return std::pair<Simplex_handle, Simplex_handle>( - root_.members_.find(sh->first), - root_.members_.find(self_siblings(sh)->parent())); + assert(dimension(sh) == 1); + return { find_vertex(sh->first), find_vertex(self_siblings(sh)->parent()) }; } /** Returns the Siblings containing a simplex.*/ @@ -541,32 +748,17 @@ class Simplex_tree { return sh->second.children(); } -// void display_simplex(Simplex_handle sh) -// { -// std::cout << " " << "[" << filtration(sh) << "] "; -// for( auto vertex : simplex_vertex_range(sh) ) -// { std::cout << vertex << " "; } -// } - - // void print(Simplex_handle sh, std::ostream& os = std::cout) - // { for(auto v : simplex_vertex_range(sh)) {os << v << " ";} - // os << std::endl; } - public: /** Returns a pointer to the root nodes of the simplex tree. */ Siblings * root() { return &root_; } - public: /** Set an upper bound for the filtration values. */ void set_filtration(Filtration_value fil) { threshold_ = fil; } - /** Set a number of simplices for the simplicial complex. */ - void set_num_simplices(unsigned int num_simplices) { - num_simplices_ = num_simplices; - } + /** Set a dimension for the simplicial complex. */ void set_dimension(int dimension) { dimension_ = dimension; @@ -580,28 +772,114 @@ class Simplex_tree { * assigned a Simplex_key corresponding to its order in the filtration (from 0 to m-1 for a * simplicial complex with m simplices). * - * The use of a depth-first traversal of the simplex tree, provided by - * complex_simplex_range(), combined with - * a stable sort is meant to optimize the order of simplices with same - * filtration value. The heuristic consists in inserting the cofaces of a - * simplex as soon as possible. - * * Will be automatically called when calling filtration_simplex_range() * if the filtration has never been initialized yet. */ void initialize_filtration() { filtration_vect_.clear(); filtration_vect_.reserve(num_simplices()); - for (auto cpx_it = complex_simplex_range().begin(); - cpx_it != complex_simplex_range().end(); ++cpx_it) { - filtration_vect_.push_back(*cpx_it); - } - - // the stable sort ensures the ordering heuristic + for (Simplex_handle sh : complex_simplex_range()) + filtration_vect_.push_back(sh); + + /* We use stable_sort here because with libstdc++ it is faster than sort. + * is_before_in_filtration is now a total order, but we used to call + * stable_sort for the following heuristic: + * The use of a depth-first traversal of the simplex tree, provided by + * complex_simplex_range(), combined with a stable sort is meant to + * optimize the order of simplices with same filtration value. The + * heuristic consists in inserting the cofaces of a simplex as soon as + * possible. + */ std::stable_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this)); } private: + /** Recursive search of cofaces + * This function uses DFS + *\param vertices contains a list of vertices, which represent the vertices of the simplex not found yet. + *\param curr_nbVertices represents the number of vertices of the simplex we reached by going through the tree. + *\param cofaces contains a list of Simplex_handle, representing all the cofaces asked. + *\param star true if we need the star of the simplex + *\param nbVertices number of vertices of the cofaces we search + * Prefix actions : When the bottom vertex matches with the current vertex in the tree, we remove the bottom vertex from vertices. + * Infix actions : Then we call or not the recursion. + * Postfix actions : Finally, we add back the removed vertex into vertices, and remove this vertex from curr_nbVertices so that we didn't change the parameters. + * If the vertices list is empty, we need to check if curr_nbVertices matches with the dimension of the cofaces asked. + */ + void rec_coface(std::vector<Vertex_handle> &vertices, Siblings *curr_sib, int curr_nbVertices, + std::vector<Simplex_handle>& cofaces, bool star, int nbVertices) { + if (!(star || curr_nbVertices <= nbVertices)) // dimension of actual simplex <= nbVertices + return; + for (Simplex_handle simplex = curr_sib->members().begin(); simplex != curr_sib->members().end(); ++simplex) { + if (vertices.empty()) { + // 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 + bool addCoface = (star || curr_nbVertices == nbVertices); + if (addCoface) + cofaces.push_back(simplex); + if ((!addCoface || star) && has_children(simplex)) // Rec call + rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices); + } else { + if (simplex->first == vertices.back()) { + // If curr_sib matches with the top vertex + bool equalDim = (star || curr_nbVertices == nbVertices); // dimension of actual simplex == nbVertices + bool addCoface = vertices.size() == 1 && equalDim; + if (addCoface) + cofaces.push_back(simplex); + if ((!addCoface || star) && has_children(simplex)) { + // Rec call + Vertex_handle tmp = vertices.back(); + vertices.pop_back(); + rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices); + vertices.push_back(tmp); + } + } else if (simplex->first > vertices.back()) { + return; + } else { + // (simplex->first < vertices.back() + if (has_children(simplex)) + rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices); + } + } + } + } + + public: + /** \brief Compute the star of a n simplex + * \param simplex represent the simplex of which we search the star + * \return Vector of Simplex_handle, empty vector if no cofaces found. + */ + + Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex) { + return cofaces_simplex_range(simplex, 0); + } + + /** \brief Compute the cofaces of a n simplex + * \param simplex represent the n-simplex of which we search the n+codimension cofaces + * \param codimension The function returns the n+codimension-cofaces of the n-simplex. If codimension = 0, + * return all cofaces (equivalent of star function) + * \return Vector of Simplex_handle, empty vector if no cofaces found. + */ + + Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension) { + Cofaces_simplex_range cofaces; + // codimension must be positive or null integer + assert(codimension >= 0); + Simplex_vertex_range rg = simplex_vertex_range(simplex); + std::vector<Vertex_handle> copy(rg.begin(), rg.end()); + if (codimension + static_cast<int>(copy.size()) > dimension_ + 1 || + (codimension == 0 && static_cast<int>(copy.size()) > dimension_)) // n+codimension greater than dimension_ + return cofaces; + // must be sorted in decreasing order + assert(std::is_sorted(copy.begin(), copy.end(), std::greater<Vertex_handle>())); + bool star = codimension == 0; + rec_coface(copy, &root_, 1, cofaces, star, codimension + static_cast<int>(copy.size())); + return cofaces; + } + + private: /** \brief Returns true iff the list of vertices of sh1 * is smaller than the list of vertices of sh2 w.r.t. * lexicographic order on the lists read in reverse. @@ -624,6 +902,7 @@ class Simplex_tree { } return ((it1 == rg1.end()) && (it2 != rg2.end())); } + /** \brief StrictWeakOrdering, for the simplices, defined by the filtration. * * It corresponds to the partial order @@ -632,15 +911,15 @@ class Simplex_tree { * to be smaller. The filtration function must be monotonic. */ struct is_before_in_filtration { explicit is_before_in_filtration(Simplex_tree * st) - : st_(st) { - } + : st_(st) { } bool operator()(const Simplex_handle sh1, const Simplex_handle sh2) const { - if (st_->filtration(sh1) != st_->filtration(sh2)) { - return st_->filtration(sh1) < st_->filtration(sh2); + // Not using st_->filtration(sh1) because it uselessly tests for null_simplex. + if (sh1->second.filtration() != sh2->second.filtration()) { + return sh1->second.filtration() < sh2->second.filtration(); } - - return st_->reverse_lexicographic_order(sh1, sh2); // is sh1 a proper subface of sh2 + // is sh1 a proper subface of sh2 + return st_->reverse_lexicographic_order(sh1, sh2); } Simplex_tree * st_; @@ -667,7 +946,8 @@ class Simplex_tree { * must be undirected_tag. */ template<class OneSkeletonGraph> void insert_graph(const OneSkeletonGraph& skel_graph) { - assert(num_simplices() == 0); // the simplex tree must be empty + // the simplex tree must be empty + assert(num_simplices() == 0); if (boost::num_vertices(skel_graph) == 0) { return; @@ -678,37 +958,37 @@ class Simplex_tree { dimension_ = 1; } - num_simplices_ = boost::num_vertices(skel_graph) - + boost::num_edges(skel_graph); root_.members_.reserve(boost::num_vertices(skel_graph)); 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) { + ++v_it) { root_.members_.emplace_hint( - root_.members_.end(), *v_it, - Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it))); + root_.members_.end(), *v_it, + Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it))); } typename boost::graph_traits<OneSkeletonGraph>::edge_iterator e_it, e_it_end; for (std::tie(e_it, e_it_end) = boost::edges(skel_graph); e_it != e_it_end; - ++e_it) { + ++e_it) { auto u = source(*e_it, skel_graph); auto v = target(*e_it, skel_graph); - if (u < v) { // count edges only once { std::swap(u,v); } // u < v + if (u < v) { + // count edges only once { std::swap(u,v); } // u < v auto sh = find_vertex(u); if (!has_children(sh)) { sh->second.assign_children(new Siblings(&root_, sh->first)); } sh->second.children()->members().emplace( - v, - Node(sh->second.children(), - boost::get(edge_filtration_t(), skel_graph, *e_it))); + v, + Node(sh->second.children(), + boost::get(edge_filtration_t(), skel_graph, *e_it))); } } } + /** \brief Expands the Simplex_tree containing only its one skeleton * until dimension max_dim. * @@ -723,7 +1003,7 @@ class Simplex_tree { void expansion(int max_dim) { dimension_ = max_dim; for (Dictionary_it root_it = root_.members_.begin(); - root_it != root_.members_.end(); ++root_it) { + root_it != root_.members_.end(); ++root_it) { if (has_children(root_it)) { siblings_expansion(root_it->second.children(), max_dim - 1); } @@ -734,7 +1014,7 @@ class Simplex_tree { private: /** \brief Recursive expansion of the simplex tree.*/ void siblings_expansion(Siblings * siblings, // must contain elements - int k) { + int k) { if (dimension_ > k) { dimension_ = k; } @@ -745,68 +1025,55 @@ class Simplex_tree { static std::vector<std::pair<Vertex_handle, Node> > inter; // static, not thread-safe. for (Dictionary_it s_h = siblings->members().begin(); - s_h != siblings->members().end(); ++s_h, ++next) { + s_h != siblings->members().end(); ++s_h, ++next) { Simplex_handle root_sh = find_vertex(s_h->first); if (has_children(root_sh)) { intersection( - inter, // output intersection - next, // begin - siblings->members().end(), // end - root_sh->second.children()->members().begin(), - root_sh->second.children()->members().end(), - s_h->second.filtration()); + inter, // output intersection + next, // begin + siblings->members().end(), // end + root_sh->second.children()->members().begin(), + root_sh->second.children()->members().end(), + s_h->second.filtration()); if (inter.size() != 0) { - this->num_simplices_ += inter.size(); Siblings * new_sib = new Siblings(siblings, // oncles - s_h->first, // parent - inter); // boost::container::ordered_unique_range_t + s_h->first, // parent + inter); // boost::container::ordered_unique_range_t inter.clear(); s_h->second.assign_children(new_sib); siblings_expansion(new_sib, k - 1); } else { - s_h->second.assign_children(siblings); // ensure the children property + // ensure the children property + s_h->second.assign_children(siblings); inter.clear(); } } } } + /** \brief Intersects Dictionary 1 [begin1;end1) with Dictionary 2 [begin2,end2) * and assigns the maximal possible Filtration_value to the Nodes. */ static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection, Dictionary_it begin1, Dictionary_it end1, Dictionary_it begin2, Dictionary_it end2, - Filtration_value filtration) { + Filtration_value filtration_) { if (begin1 == end1 || begin2 == end2) return; // ----->> while (true) { if (begin1->first == begin2->first) { - intersection.push_back( - std::pair<Vertex_handle, Node>( - begin1->first, - Node(NULL, maximum(begin1->second.filtration(), begin2->second.filtration(), filtration)))); - ++begin1; - ++begin2; - if (begin1 == end1 || begin2 == end2) + Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_}); + intersection.emplace_back(begin1->first, Node(nullptr, filt)); + if (++begin1 == end1 || ++begin2 == end2) + return; // ----->> + } else if (begin1->first < begin2->first) { + if (++begin1 == end1) + return; + } else /* begin1->first > begin2->first */ { + if (++begin2 == end2) return; // ----->> - } else { - if (begin1->first < begin2->first) { - ++begin1; - if (begin1 == end1) - return; - } else { - ++begin2; - if (begin2 == end2) - return; // ----->> - } } } } - /** Maximum over 3 values.*/ - static Filtration_value maximum(Filtration_value a, Filtration_value b, - Filtration_value c) { - Filtration_value max = (a < b) ? b : a; - return ((max < c) ? c : max); - } public: /** \brief Write the hasse diagram of the simplicial complex in os. @@ -817,7 +1084,7 @@ class Simplex_tree { * of the simplex, and fil is its filtration value. */ void print_hasse(std::ostream& os) { os << num_simplices() << " " << std::endl; - for (auto sh : filtration_simplex_range(Indexing_tag())) { + for (auto sh : filtration_simplex_range()) { os << dimension(sh) << " "; for (auto b_sh : boundary_simplex_range(sh)) { os << key(b_sh) << " "; @@ -831,7 +1098,6 @@ class Simplex_tree { /** \brief Upper bound on the filtration values of the simplices.*/ Filtration_value threshold_; /** \brief Total number of simplices in the complex, without the empty simplex.*/ - unsigned int num_simplices_; /** \brief Set of simplex tree Nodes representing the vertices.*/ Siblings root_; /** \brief Simplices ordered according to a filtration.*/ @@ -841,8 +1107,9 @@ class Simplex_tree { }; // Print a Simplex_tree in os. -template<typename T1, typename T2, typename T3> -std::ostream& operator<<(std::ostream & os, Simplex_tree<T1, T2, T3> & st) { + +template<typename...T> +std::ostream& operator<<(std::ostream & os, Simplex_tree<T...> & st) { for (auto sh : st.filtration_simplex_range()) { os << st.dimension(sh) << " "; for (auto v : st.simplex_vertex_range(sh)) { @@ -852,35 +1119,35 @@ std::ostream& operator<<(std::ostream & os, Simplex_tree<T1, T2, T3> & st) { } return os; } -template<typename T1, typename T2, typename T3> -std::istream& operator>>(std::istream & is, Simplex_tree<T1, T2, T3> & st) { - // assert(st.num_simplices() == 0); - std::vector<typename Simplex_tree<T1, T2, T3>::Vertex_handle> simplex; - typename Simplex_tree<T1, T2, T3>::Filtration_value fil; - typename Simplex_tree<T1, T2, T3>::Filtration_value max_fil = 0; +template<typename...T> +std::istream& operator>>(std::istream & is, Simplex_tree<T...> & st) { + typedef Simplex_tree<T...> ST; + std::vector<typename ST::Vertex_handle> simplex; + typename ST::Filtration_value fil; + typename ST::Filtration_value max_fil = 0; int max_dim = -1; - size_t num_simplices = 0; - while (read_simplex(is, simplex, fil)) { // read all simplices in the file as a list of vertices - ++num_simplices; - int dim = static_cast<int>(simplex.size() - 1); // Warning : simplex_size needs to be casted in int - Can be 0 + while (read_simplex(is, simplex, fil)) { + // read all simplices in the file as a list of vertices + // Warning : simplex_size needs to be casted in int - Can be 0 + int dim = static_cast<int> (simplex.size() - 1); if (max_dim < dim) { max_dim = dim; } if (max_fil < fil) { max_fil = fil; } - st.insert_simplex(simplex, fil); // insert every simplex in the simplex tree + // insert every simplex in the simplex tree + st.insert_simplex(simplex, fil); simplex.clear(); } - st.set_num_simplices(num_simplices); st.set_dimension(max_dim); st.set_filtration(max_fil); return is; } - /** @} */ // end defgroup simplex_tree + } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_H_ +#endif // SIMPLEX_TREE_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h index 06462c88..372ef329 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_iterators.h @@ -20,10 +20,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ +#ifndef SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ +#define SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ #include <boost/iterator/iterator_facade.hpp> +#include <boost/version.hpp> +#if BOOST_VERSION >= 105600 +# include <boost/container/static_vector.hpp> +#endif #include <vector> @@ -131,8 +135,7 @@ class Simplex_tree_boundary_simplex_iterator : public boost::iterator_facade< } Siblings * for_sib = sib_; - for (typename std::vector<Vertex_handle>::reverse_iterator rit = suffix_ - .rbegin(); rit != suffix_.rend(); ++rit) { + for (auto rit = suffix_.rbegin(); rit != suffix_.rend(); ++rit) { sh_ = for_sib->find(*rit); for_sib = sh_->second.children(); } @@ -142,9 +145,18 @@ class Simplex_tree_boundary_simplex_iterator : public boost::iterator_facade< sib_ = sib_->oncles(); } + // Most of the storage should be moved to the range, iterators should be light. Vertex_handle last_; // last vertex of the simplex Vertex_handle next_; // next vertex to push in suffix_ +#if BOOST_VERSION >= 105600 + // 40 seems a conservative bound on the dimension of a Simplex_tree for now, + // as it would not fit on the biggest hard-drive. + boost::container::static_vector<Vertex_handle, 40> suffix_; + // static_vector still has some overhead compared to a trivial hand-made + // version using std::aligned_storage, or compared to making suffix_ static. +#else std::vector<Vertex_handle> suffix_; +#endif Siblings * sib_; // where the next search will start from Simplex_handle sh_; // current Simplex_handle in the boundary SimplexTree * st_; // simplex containing the simplicial complex @@ -303,4 +315,4 @@ class Simplex_tree_skeleton_simplex_iterator : public boost::iterator_facade< /* @} */ // end addtogroup simplex_tree } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ +#endif // SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h index 1f1a34cc..25d4888a 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ +#ifndef SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ +#define SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ #include <vector> @@ -39,65 +39,34 @@ namespace Gudhi { * It stores explicitely its own filtration value and its own Simplex_key. */ template<class SimplexTree> -class Simplex_tree_node_explicit_storage { - public: +struct Simplex_tree_node_explicit_storage : SimplexTree::Filtration_simplex_base, SimplexTree::Key_simplex_base { typedef typename SimplexTree::Siblings Siblings; typedef typename SimplexTree::Filtration_value Filtration_value; typedef typename SimplexTree::Simplex_key Simplex_key; - // Default constructor. - Simplex_tree_node_explicit_storage() - : children_(NULL), - simplex_key_(-1), - filtration_(0) { - } - - Simplex_tree_node_explicit_storage(Siblings * sib, - Filtration_value filtration) - : children_(sib), - simplex_key_(-1), - filtration_(filtration) { - } - - void assign_key(Simplex_key key) { - simplex_key_ = key; + Simplex_tree_node_explicit_storage(Siblings * sib = nullptr, + Filtration_value filtration = 0) + : children_(sib) { + this->assign_filtration(filtration); } /* - * Assign a children to the node + * Assign children to the node */ void assign_children(Siblings * children) { children_ = children; } - /* - * - */ - void assign_filtration(double filtration_value) { - filtration_ = filtration_value; - } - - Filtration_value filtration() { - return filtration_; - } /* Careful -> children_ can be NULL*/ Siblings * children() { return children_; } - Simplex_key key() { - return simplex_key_; - } - private: Siblings * children_; - - // Data attached to simplex, explicit storage - Simplex_key simplex_key_; - Filtration_value filtration_; // value in the filtration }; /* @} */ // end addtogroup simplex_tree } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ +#endif // SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h index 977fafa1..158ee1f7 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/Simplex_tree_siblings.h @@ -20,11 +20,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ +#ifndef SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ +#define SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ -#include "boost/container/flat_map.hpp" -#include "Simplex_tree_node_explicit_storage.h" +#include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h> + +#include <boost/container/flat_map.hpp> #include <utility> #include <vector> @@ -71,14 +72,14 @@ class Simplex_tree_siblings { /* \brief Constructor with initialized set of members. * * 'members' must be sorted and unique.*/ - Simplex_tree_siblings(Simplex_tree_siblings * oncles, Vertex_handle parent, - const std::vector<std::pair<Vertex_handle, Node> > & members) + template<typename RandomAccessVertexRange> + Simplex_tree_siblings(Simplex_tree_siblings * oncles, Vertex_handle parent, const RandomAccessVertexRange & members) : oncles_(oncles), parent_(parent), members_(boost::container::ordered_unique_range, members.begin(), members.end()) { - for (auto map_it = members_.begin(); map_it != members_.end(); map_it++) { - map_it->second.assign_children(this); + for (auto& map_el : members_) { + map_el.second.assign_children(this); } } @@ -90,19 +91,12 @@ class Simplex_tree_siblings { * present in the node. */ void insert(Vertex_handle v, Filtration_value filtration_value) { - typename Dictionary::iterator sh = members_.find(v); - if (sh != members_.end() && sh->second.filtration() > filtration_value) { - sh->second.assign_filtration(filtration_value); - return; - } - if (sh == members_.end()) { - members_.insert( - std::pair<Vertex_handle, Node>(v, Node(this, filtration_value))); - return; - } + auto ins = members_.emplace(v, Node(this, filtration_value)); + if (!ins.second && filtration(ins.first) > filtration_value) + ins.first->second.assign_filtration(filtration_value); } - typename Dictionary::iterator find(Vertex_handle v) { + Dictionary_it find(Vertex_handle v) { return members_.find(v); } @@ -110,7 +104,7 @@ class Simplex_tree_siblings { return oncles_; } - Vertex_handle parent() { + Vertex_handle parent() const { return parent_; } @@ -118,7 +112,7 @@ class Simplex_tree_siblings { return members_; } - size_t size() { + size_t size() const { return members_.size(); } @@ -130,4 +124,4 @@ class Simplex_tree_siblings { /* @} */ // end addtogroup simplex_tree } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ +#endif // SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_ diff --git a/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h b/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h index 69ffa44b..0adeb46d 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree/indexing_tag.h @@ -20,8 +20,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_INDEXING_TAG_H_ -#define SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_INDEXING_TAG_H_ +#ifndef SIMPLEX_TREE_INDEXING_TAG_H_ +#define SIMPLEX_TREE_INDEXING_TAG_H_ namespace Gudhi { @@ -36,4 +36,4 @@ struct linear_indexing_tag { // struct zigzag_indexing_tag {}; } // namespace Gudhi -#endif // SRC_SIMPLEX_TREE_INCLUDE_GUDHI_SIMPLEX_TREE_INDEXING_TAG_H_ +#endif // SIMPLEX_TREE_INDEXING_TAG_H_ diff --git a/src/Simplex_tree/test/CMakeLists.txt b/src/Simplex_tree/test/CMakeLists.txt index b6a1c0b6..c9eae163 100644 --- a/src/Simplex_tree/test/CMakeLists.txt +++ b/src/Simplex_tree/test/CMakeLists.txt @@ -17,6 +17,9 @@ endif() add_executable ( SimplexTreeUT simplex_tree_unit_test.cpp ) target_link_libraries(SimplexTreeUT ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +# Do not forget to copy test files in current binary dir +file(COPY "simplex_tree_for_unit_test.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + # Unitary tests add_test(NAME SimplexTreeUT COMMAND ${CMAKE_CURRENT_BINARY_DIR}/SimplexTreeUT diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp index 6b0a1f3d..fff00d77 100644 --- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp @@ -1,17 +1,16 @@ -#define BOOST_TEST_MODULE simplex_tree test -#include <boost/test/included/unit_test.hpp> -#include <boost/system/error_code.hpp> -#include <boost/chrono/thread_clock.hpp> #include <iostream> #include <string> - +#include <algorithm> #include <utility> // std::pair, std::make_pair - #include <cmath> // float comparison #include <limits> -#include "gudhi/graph_simplicial_complex.h" -#include "gudhi/reader_utils.h" +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "simplex_tree" +#include <boost/test/unit_test.hpp> + +// ^ +// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined. #include "gudhi/Simplex_tree.h" using namespace Gudhi; @@ -21,7 +20,7 @@ typedef std::pair<typeST::Simplex_handle, bool> typePairSimplexBool; typedef std::vector<Vertex_handle> typeVectorVertex; typedef std::pair<typeVectorVertex, Filtration_value> typeSimplex; -const Vertex_handle DEFAULT_VERTEX_HANDLE = (const Vertex_handle) -1; +const Vertex_handle DEFAULT_VERTEX_HANDLE = (const Vertex_handle) - 1; const Filtration_value DEFAULT_FILTRATION_VALUE = (const Filtration_value) 0.0; void test_empty_simplex_tree(typeST& tst) { @@ -40,55 +39,52 @@ void test_iterators_on_empty_simplex_tree(typeST& tst) { std::cout << "Iterator on vertices: " << std::endl; for (auto vertex : tst.complex_vertex_range()) { std::cout << "vertice:" << vertex << std::endl; - BOOST_CHECK(false); // shall be empty + BOOST_CHECK(false); // shall be empty } std::cout << "Iterator on simplices: " << std::endl; for (auto simplex : tst.complex_simplex_range()) { - BOOST_CHECK(simplex != simplex); // shall be empty - to remove warning of non-used simplex + BOOST_CHECK(simplex != simplex); // shall be empty - to remove warning of non-used simplex } std::cout << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; for (auto f_simplex : tst.filtration_simplex_range()) { - BOOST_CHECK(false); // shall be empty + BOOST_CHECK(false); // shall be empty std::cout << "test_iterators_on_empty_simplex_tree - filtration=" << tst.filtration(f_simplex) << std::endl; } } -BOOST_AUTO_TEST_CASE( simplex_tree_when_empty ) -{ +BOOST_AUTO_TEST_CASE(simplex_tree_when_empty) { const Filtration_value DEFAULT_FILTRATION_VALUE = 0; - // TEST OF DEFAULT CONSTRUCTOR std::cout << "********************************************************************" << std::endl; std::cout << "TEST OF DEFAULT CONSTRUCTOR" << std::endl; typeST st; - test_empty_simplex_tree (st); + test_empty_simplex_tree(st); - test_iterators_on_empty_simplex_tree (st); + test_iterators_on_empty_simplex_tree(st); // TEST OF EMPTY INSERTION std::cout << "TEST OF EMPTY INSERTION" << std::endl; typeVectorVertex simplexVectorEmpty; BOOST_CHECK(simplexVectorEmpty.empty() == true); typePairSimplexBool returnEmptyValue = st.insert_simplex(simplexVectorEmpty, - DEFAULT_FILTRATION_VALUE); + DEFAULT_FILTRATION_VALUE); BOOST_CHECK(returnEmptyValue.first == typeST::Simplex_handle(NULL)); BOOST_CHECK(returnEmptyValue.second == true); - test_empty_simplex_tree (st); + test_empty_simplex_tree(st); - test_iterators_on_empty_simplex_tree (st); + test_iterators_on_empty_simplex_tree(st); } bool AreAlmostTheSame(float a, float b) { return std::fabs(a - b) < std::numeric_limits<float>::epsilon(); } -BOOST_AUTO_TEST_CASE( simplex_tree_from_file ) -{ +BOOST_AUTO_TEST_CASE(simplex_tree_from_file) { // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; std::cout << "TEST OF SIMPLEX TREE FROM A FILE" << std::endl; @@ -108,16 +104,16 @@ BOOST_AUTO_TEST_CASE( simplex_tree_from_file ) BOOST_CHECK(st.filtration() == 0.4); int previous_size = 0; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { // Size of simplex int size = 0; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + // Remove warning + (void) vertex; size++; } - BOOST_CHECK(AreAlmostTheSame(st.filtration(f_simplex),(0.1* size))); // Specific test: filtration = 0.1 * simplex_size - BOOST_CHECK(previous_size <= size);// Check list is sorted (because of sorted filtrations in simplex_tree.txt) + BOOST_CHECK(AreAlmostTheSame(st.filtration(f_simplex), (0.1 * size))); // Specific test: filtration = 0.1 * simplex_size + BOOST_CHECK(previous_size <= size); // Check list is sorted (because of sorted filtrations in simplex_tree.txt) previous_size = size; } simplex_tree_stream.close(); @@ -127,13 +123,13 @@ void test_simplex_tree_contains(typeST& simplexTree, typeSimplex& simplex, int p auto f_simplex = simplexTree.filtration_simplex_range().begin() + pos; std::cout << "test_simplex_tree_contains - filtration=" << simplexTree.filtration(*f_simplex) << "||" << simplex.second << std::endl; - BOOST_CHECK( AreAlmostTheSame(simplexTree.filtration(*f_simplex),simplex.second) ); + BOOST_CHECK(AreAlmostTheSame(simplexTree.filtration(*f_simplex), simplex.second)); - int simplexIndex=simplex.first.size()-1; - for( auto vertex : simplexTree.simplex_vertex_range(*f_simplex) ) - { + int simplexIndex = simplex.first.size() - 1; + std::sort(simplex.first.begin(), simplex.first.end()); // if the simplex wasn't sorted, the next test could fail + for (auto vertex : simplexTree.simplex_vertex_range(*f_simplex)) { std::cout << "test_simplex_tree_contains - vertex=" << vertex << "||" << simplex.first.at(simplexIndex) << std::endl; - BOOST_CHECK(vertex == simplex.first.at(simplexIndex)); + BOOST_CHECK(vertex == simplex.first.at(simplexIndex)); BOOST_CHECK(simplexIndex >= 0); simplexIndex--; } @@ -141,7 +137,7 @@ void test_simplex_tree_contains(typeST& simplexTree, typeSimplex& simplex, int p void test_simplex_tree_insert_returns_true(const typePairSimplexBool& returnValue) { BOOST_CHECK(returnValue.second == true); - typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator + typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator BOOST_CHECK(shReturned != typeST::Simplex_handle(NULL)); } @@ -162,24 +158,26 @@ void set_and_test_simplex_tree_dim_fil(typeST& simplexTree, int vectorSize, cons std::cout << " set_and_test_simplex_tree_dim_fil - max_fil=" << max_fil << std::endl; } - unsigned int nb_simplices = simplexTree.num_simplices() + 1; - simplexTree.set_num_simplices(nb_simplices); BOOST_CHECK(simplexTree.dimension() == dim_max); BOOST_CHECK(AreAlmostTheSame(simplexTree.filtration(), max_fil)); - BOOST_CHECK(simplexTree.num_simplices() == nb_simplices); + + // Another way to count simplices: + size_t num_simp = 0; + for (auto f_simplex : simplexTree.complex_simplex_range()) { + // Remove warning + (void) f_simplex; + num_simp++; + } + + BOOST_CHECK(simplexTree.num_simplices() == num_simp); } -BOOST_AUTO_TEST_CASE( simplex_tree_insertion ) -{ +BOOST_AUTO_TEST_CASE(simplex_tree_insertion) { const Filtration_value FIRST_FILTRATION_VALUE = 0.1; const Filtration_value SECOND_FILTRATION_VALUE = 0.2; const Filtration_value THIRD_FILTRATION_VALUE = 0.3; const Filtration_value FOURTH_FILTRATION_VALUE = 0.4; - Vertex_handle FIRST_VERTEX_HANDLE = (Vertex_handle) 0; - Vertex_handle SECOND_VERTEX_HANDLE = (Vertex_handle) 1; - Vertex_handle THIRD_VERTEX_HANDLE = (Vertex_handle) 2; - Vertex_handle FOURTH_VERTEX_HANDLE = (Vertex_handle) 3; // TEST OF INSERTION std::cout << "********************************************************************" << std::endl; @@ -188,171 +186,131 @@ BOOST_AUTO_TEST_CASE( simplex_tree_insertion ) // ++ FIRST std::cout << " - INSERT 0" << std::endl; - typeVectorVertex firstSimplexVector; - firstSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( firstSimplexVector.size() == 1 ); - typeSimplex firstSimplex = std::make_pair( - firstSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - typePairSimplexBool returnValue = st.insert_simplex(firstSimplex.first, - firstSimplex.second); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex firstSimplexVector{0}; + BOOST_CHECK(firstSimplexVector.size() == 1); + typeSimplex firstSimplex = std::make_pair(firstSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + typePairSimplexBool returnValue = st.insert_simplex(firstSimplex.first, firstSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, firstSimplexVector.size(), firstSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)1 ); + BOOST_CHECK(st.num_vertices() == (size_t) 1); // ++ SECOND std::cout << " - INSERT 1" << std::endl; - typeVectorVertex secondSimplexVector; - secondSimplexVector.push_back(SECOND_VERTEX_HANDLE); - BOOST_CHECK( secondSimplexVector.size() == 1 ); - typeSimplex secondSimplex = std::make_pair( - secondSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( secondSimplex.first, secondSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex secondSimplexVector{1}; + BOOST_CHECK(secondSimplexVector.size() == 1); + typeSimplex secondSimplex = std::make_pair(secondSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + returnValue = st.insert_simplex(secondSimplex.first, secondSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, secondSimplexVector.size(), secondSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)2 ); + BOOST_CHECK(st.num_vertices() == (size_t) 2); // ++ THIRD std::cout << " - INSERT (0,1)" << std::endl; - typeVectorVertex thirdSimplexVector; - thirdSimplexVector.push_back(FIRST_VERTEX_HANDLE); - thirdSimplexVector.push_back(SECOND_VERTEX_HANDLE); - BOOST_CHECK( thirdSimplexVector.size() == 2 ); - typeSimplex thirdSimplex = std::make_pair( - thirdSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( thirdSimplex.first, thirdSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex thirdSimplexVector{0, 1}; + BOOST_CHECK(thirdSimplexVector.size() == 2); + typeSimplex thirdSimplex = std::make_pair(thirdSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(thirdSimplex.first, thirdSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, thirdSimplexVector.size(), thirdSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)2 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 2); // Not incremented !! // ++ FOURTH std::cout << " - INSERT 2" << std::endl; - typeVectorVertex fourthSimplexVector; - fourthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - BOOST_CHECK( fourthSimplexVector.size() == 1 ); - typeSimplex fourthSimplex = std::make_pair( - fourthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( fourthSimplex.first, fourthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex fourthSimplexVector{2}; + BOOST_CHECK(fourthSimplexVector.size() == 1); + typeSimplex fourthSimplex = std::make_pair(fourthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + returnValue = st.insert_simplex(fourthSimplex.first, fourthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, fourthSimplexVector.size(), fourthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); + BOOST_CHECK(st.num_vertices() == (size_t) 3); // ++ FIFTH std::cout << " - INSERT (2,0)" << std::endl; - typeVectorVertex fifthSimplexVector; - fifthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - fifthSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( fifthSimplexVector.size() == 2 ); - typeSimplex fifthSimplex = std::make_pair( - fifthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( fifthSimplex.first, fifthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex fifthSimplexVector{2, 0}; + BOOST_CHECK(fifthSimplexVector.size() == 2); + typeSimplex fifthSimplex = std::make_pair(fifthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(fifthSimplex.first, fifthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, fifthSimplexVector.size(), fifthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 3); // Not incremented !! // ++ SIXTH std::cout << " - INSERT (2,1)" << std::endl; - typeVectorVertex sixthSimplexVector; - sixthSimplexVector.push_back(THIRD_VERTEX_HANDLE); - sixthSimplexVector.push_back(SECOND_VERTEX_HANDLE); - BOOST_CHECK( sixthSimplexVector.size() == 2 ); - typeSimplex sixthSimplex = std::make_pair( - sixthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( sixthSimplex.first, sixthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex sixthSimplexVector{2, 1}; + BOOST_CHECK(sixthSimplexVector.size() == 2); + typeSimplex sixthSimplex = std::make_pair(sixthSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(sixthSimplex.first, sixthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, sixthSimplexVector.size(), sixthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 3); // Not incremented !! // ++ SEVENTH std::cout << " - INSERT (2,1,0)" << std::endl; - typeVectorVertex seventhSimplexVector; - seventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - seventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - seventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( seventhSimplexVector.size() == 3 ); - typeSimplex seventhSimplex = std::make_pair( - seventhSimplexVector, Filtration_value(THIRD_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( seventhSimplex.first, seventhSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex seventhSimplexVector{2, 1, 0}; + BOOST_CHECK(seventhSimplexVector.size() == 3); + typeSimplex seventhSimplex = std::make_pair(seventhSimplexVector, Filtration_value(THIRD_FILTRATION_VALUE)); + returnValue = st.insert_simplex(seventhSimplex.first, seventhSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, seventhSimplexVector.size(), seventhSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 3); // Not incremented !! // ++ EIGHTH std::cout << " - INSERT 3" << std::endl; - typeVectorVertex eighthSimplexVector; - eighthSimplexVector.push_back(FOURTH_VERTEX_HANDLE); - BOOST_CHECK( eighthSimplexVector.size() == 1 ); - typeSimplex eighthSimplex = std::make_pair( - eighthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( eighthSimplex.first, eighthSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex eighthSimplexVector{3}; + BOOST_CHECK(eighthSimplexVector.size() == 1); + typeSimplex eighthSimplex = std::make_pair(eighthSimplexVector, Filtration_value(FIRST_FILTRATION_VALUE)); + returnValue = st.insert_simplex(eighthSimplex.first, eighthSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, eighthSimplexVector.size(), eighthSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); + BOOST_CHECK(st.num_vertices() == (size_t) 4); // ++ NINETH std::cout << " - INSERT (3,0)" << std::endl; - typeVectorVertex ninethSimplexVector; - ninethSimplexVector.push_back(FOURTH_VERTEX_HANDLE); - ninethSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( ninethSimplexVector.size() == 2 ); - typeSimplex ninethSimplex = std::make_pair( - ninethSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( ninethSimplex.first, ninethSimplex.second ); - - test_simplex_tree_insert_returns_true (returnValue); + typeVectorVertex ninethSimplexVector{3, 0}; + BOOST_CHECK(ninethSimplexVector.size() == 2); + typeSimplex ninethSimplex = std::make_pair(ninethSimplexVector, Filtration_value(SECOND_FILTRATION_VALUE)); + returnValue = st.insert_simplex(ninethSimplex.first, ninethSimplex.second); + + test_simplex_tree_insert_returns_true(returnValue); set_and_test_simplex_tree_dim_fil(st, ninethSimplexVector.size(), ninethSimplex.second); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented !! + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! // ++ TENTH std::cout << " - INSERT 0 (already inserted)" << std::endl; - typeVectorVertex tenthSimplexVector; - tenthSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( tenthSimplexVector.size() == 1 ); - typeSimplex tenthSimplex = std::make_pair( - tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); // With a different filtration value - returnValue = - st.insert_simplex ( tenthSimplex.first, tenthSimplex.second ); + typeVectorVertex tenthSimplexVector{0}; + BOOST_CHECK(tenthSimplexVector.size() == 1); + // With a different filtration value + typeSimplex tenthSimplex = std::make_pair(tenthSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); + returnValue = st.insert_simplex(tenthSimplex.first, tenthSimplex.second); BOOST_CHECK(returnValue.second == false); - typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator + typeST::Simplex_handle shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator BOOST_CHECK(shReturned == typeST::Simplex_handle(NULL)); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented !! - BOOST_CHECK( st.dimension() == dim_max ); - BOOST_CHECK( AreAlmostTheSame(st.filtration(), max_fil) ); + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! + BOOST_CHECK(st.dimension() == dim_max); + BOOST_CHECK(AreAlmostTheSame(st.filtration(), max_fil)); // ++ ELEVENTH std::cout << " - INSERT (2,1,0) (already inserted)" << std::endl; - typeVectorVertex eleventhSimplexVector; - eleventhSimplexVector.push_back(THIRD_VERTEX_HANDLE); - eleventhSimplexVector.push_back(SECOND_VERTEX_HANDLE); - eleventhSimplexVector.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( eleventhSimplexVector.size() == 3 ); - typeSimplex eleventhSimplex = std::make_pair( - eleventhSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); - returnValue = - st.insert_simplex ( eleventhSimplex.first, eleventhSimplex.second ); + typeVectorVertex eleventhSimplexVector{2, 1, 0}; + BOOST_CHECK(eleventhSimplexVector.size() == 3); + typeSimplex eleventhSimplex = std::make_pair(eleventhSimplexVector, Filtration_value(FOURTH_FILTRATION_VALUE)); + returnValue = st.insert_simplex(eleventhSimplex.first, eleventhSimplex.second); BOOST_CHECK(returnValue.second == false); - shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator + shReturned = returnValue.first; // Simplex_handle = boost::container::flat_map< Vertex_handle, Node >::iterator BOOST_CHECK(shReturned == typeST::Simplex_handle(NULL)); - BOOST_CHECK( st.num_vertices() == (size_t)4 );// Not incremented !! - BOOST_CHECK( st.dimension() == dim_max ); - BOOST_CHECK( AreAlmostTheSame(st.filtration(), max_fil) ); + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! + BOOST_CHECK(st.dimension() == dim_max); + BOOST_CHECK(AreAlmostTheSame(st.filtration(), max_fil)); /* Inserted simplex: */ /* 1 */ @@ -372,119 +330,153 @@ BOOST_AUTO_TEST_CASE( simplex_tree_insertion ) // [0.3] 2 1 0 // !! Be careful, simplex are sorted by filtration value on insertion !! std::cout << "simplex_tree_insertion - first - 0" << std::endl; - test_simplex_tree_contains(st, firstSimplex, 0);// (0) -> 0 + test_simplex_tree_contains(st, firstSimplex, 0); // (0) -> 0 std::cout << "simplex_tree_insertion - second - 1" << std::endl; - test_simplex_tree_contains(st, secondSimplex, 1);// (1) -> 1 + test_simplex_tree_contains(st, secondSimplex, 1); // (1) -> 1 std::cout << "simplex_tree_insertion - third - 4" << std::endl; - test_simplex_tree_contains(st, thirdSimplex, 4);// (0,1) -> 4 + test_simplex_tree_contains(st, thirdSimplex, 4); // (0,1) -> 4 std::cout << "simplex_tree_insertion - fourth - 2" << std::endl; - test_simplex_tree_contains(st, fourthSimplex, 2);// (2) -> 2 + test_simplex_tree_contains(st, fourthSimplex, 2); // (2) -> 2 std::cout << "simplex_tree_insertion - fifth - 5" << std::endl; - test_simplex_tree_contains(st, fifthSimplex, 5);// (2,0) -> 5 + test_simplex_tree_contains(st, fifthSimplex, 5); // (2,0) -> 5 std::cout << "simplex_tree_insertion - sixth - 6" << std::endl; - test_simplex_tree_contains(st, sixthSimplex, 6);//(2,1) -> 6 + test_simplex_tree_contains(st, sixthSimplex, 6); //(2,1) -> 6 std::cout << "simplex_tree_insertion - seventh - 8" << std::endl; - test_simplex_tree_contains(st, seventhSimplex, 8);// (2,1,0) -> 8 + test_simplex_tree_contains(st, seventhSimplex, 8); // (2,1,0) -> 8 std::cout << "simplex_tree_insertion - eighth - 3" << std::endl; - test_simplex_tree_contains(st, eighthSimplex, 3);// (3) -> 3 + test_simplex_tree_contains(st, eighthSimplex, 3); // (3) -> 3 std::cout << "simplex_tree_insertion - nineth - 7" << std::endl; - test_simplex_tree_contains(st, ninethSimplex, 7);// (3,0) -> 7 + test_simplex_tree_contains(st, ninethSimplex, 7); // (3,0) -> 7 // Display the Simplex_tree - Can not be done in the middle of 2 inserts std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; std::cout << " - dimension " << st.dimension() << " - filtration " << st.filtration() << std::endl; std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { - std::cout << (int)vertex << " "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; } std::cout << std::endl; } } -BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) -{ - Vertex_handle FIRST_VERTEX_HANDLE = (Vertex_handle)0; - Vertex_handle SECOND_VERTEX_HANDLE = (Vertex_handle) 1; - Vertex_handle THIRD_VERTEX_HANDLE = (Vertex_handle) 2; - Vertex_handle FOURTH_VERTEX_HANDLE = (Vertex_handle) 3; - Vertex_handle FIFTH_VERTEX_HANDLE = (Vertex_handle) 4; - Vertex_handle SIXTH_VERTEX_HANDLE = (Vertex_handle) 5; - Vertex_handle SEVENTH_VERTEX_HANDLE = (Vertex_handle) 6; - Vertex_handle EIGHTH_VERTEX_HANDLE = (Vertex_handle) 7; +bool sort_in_decr_order (Vertex_handle i,Vertex_handle j) { return (i>j); } - // TEST OF INSERTION +BOOST_AUTO_TEST_CASE(NSimplexAndSubfaces_tree_insertion) { std::cout << "********************************************************************" << std::endl; - std::cout << "TEST OF INSERTION" << std::endl; + std::cout << "TEST OF RECURSIVE INSERTION" << std::endl; typeST st; + typePairSimplexBool returnValue; + int position = 0; // ++ FIRST std::cout << " - INSERT (2,1,0)" << std::endl; - typeVectorVertex SimplexVector1; - SimplexVector1.push_back(THIRD_VERTEX_HANDLE); - SimplexVector1.push_back(SECOND_VERTEX_HANDLE); - SimplexVector1.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector1.size() == 3 ); - st.insert_simplex_and_subfaces ( SimplexVector1 ); - - BOOST_CHECK( st.num_vertices() == (size_t)3 ); // +3 (2, 1 and 0 are not existing) + typeVectorVertex SimplexVector1{2, 1, 0}; + BOOST_CHECK(SimplexVector1.size() == 3); + returnValue = st.insert_simplex_and_subfaces(SimplexVector1); + + BOOST_CHECK(st.num_vertices() == (size_t) 3); // +3 (2, 1 and 0 are not existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector1.begin(), SimplexVector1.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector1[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector1[position]); + position++; + } // ++ SECOND std::cout << " - INSERT 3" << std::endl; - typeVectorVertex SimplexVector2; - SimplexVector2.push_back(FOURTH_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector2.size() == 1 ); - st.insert_simplex_and_subfaces ( SimplexVector2 ); - - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // +1 (3 is not existing) + typeVectorVertex SimplexVector2{3}; + BOOST_CHECK(SimplexVector2.size() == 1); + returnValue = st.insert_simplex_and_subfaces(SimplexVector2); + + BOOST_CHECK(st.num_vertices() == (size_t) 4); // +1 (3 is not existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector2.begin(), SimplexVector2.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector2[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector2[position]); + position++; + } // ++ THIRD std::cout << " - INSERT (0,3)" << std::endl; - typeVectorVertex SimplexVector3; - SimplexVector3.push_back(FOURTH_VERTEX_HANDLE); - SimplexVector3.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector3.size() == 2 ); - st.insert_simplex_and_subfaces ( SimplexVector3 ); - - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented (all are existing) + typeVectorVertex SimplexVector3{3, 0}; + BOOST_CHECK(SimplexVector3.size() == 2); + returnValue = st.insert_simplex_and_subfaces(SimplexVector3); + + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented (all are existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector3.begin(), SimplexVector3.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector3[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector3[position]); + position++; + } // ++ FOURTH std::cout << " - INSERT (1,0) (already inserted)" << std::endl; - typeVectorVertex SimplexVector4; - SimplexVector4.push_back(SECOND_VERTEX_HANDLE); - SimplexVector4.push_back(FIRST_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector4.size() == 2 ); - st.insert_simplex_and_subfaces ( SimplexVector4 ); + typeVectorVertex SimplexVector4{1, 0}; + BOOST_CHECK(SimplexVector4.size() == 2); + returnValue = st.insert_simplex_and_subfaces(SimplexVector4); - BOOST_CHECK( st.num_vertices() == (size_t)4 ); // Not incremented (all are existing) + BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented (all are existing) + + // Check it was not inserted (already there from {2,1,0} insertion) + BOOST_CHECK(false == returnValue.second); // ++ FIFTH std::cout << " - INSERT (3,4,5)" << std::endl; - typeVectorVertex SimplexVector5; - SimplexVector5.push_back(FOURTH_VERTEX_HANDLE); - SimplexVector5.push_back(FIFTH_VERTEX_HANDLE); - SimplexVector5.push_back(SIXTH_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector5.size() == 3 ); - st.insert_simplex_and_subfaces ( SimplexVector5 ); - - BOOST_CHECK( st.num_vertices() == (size_t)6 ); + typeVectorVertex SimplexVector5{3, 4, 5}; + BOOST_CHECK(SimplexVector5.size() == 3); + returnValue = st.insert_simplex_and_subfaces(SimplexVector5); + + BOOST_CHECK(st.num_vertices() == (size_t) 6); + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector5.begin(), SimplexVector5.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector5[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector5[position]); + position++; + } // ++ SIXTH std::cout << " - INSERT (0,1,6,7)" << std::endl; - typeVectorVertex SimplexVector6; - SimplexVector6.push_back(FIRST_VERTEX_HANDLE); - SimplexVector6.push_back(SECOND_VERTEX_HANDLE); - SimplexVector6.push_back(SEVENTH_VERTEX_HANDLE); - SimplexVector6.push_back(EIGHTH_VERTEX_HANDLE); - BOOST_CHECK( SimplexVector6.size() == 4 ); - st.insert_simplex_and_subfaces ( SimplexVector6 ); - - BOOST_CHECK( st.num_vertices() == (size_t)8 ); // +2 (6 and 7 are not existing - 0 and 1 are already existing) - + typeVectorVertex SimplexVector6{0, 1, 6, 7}; + BOOST_CHECK(SimplexVector6.size() == 4); + returnValue = st.insert_simplex_and_subfaces(SimplexVector6); + + BOOST_CHECK(st.num_vertices() == (size_t) 8); // +2 (6 and 7 are not existing - 0 and 1 are already existing) + + // Check it is well inserted + BOOST_CHECK(true == returnValue.second); + position = 0; + std::sort(SimplexVector6.begin(), SimplexVector6.end(), sort_in_decr_order); + for (auto vertex : st.simplex_vertex_range(returnValue.first)) { + // Check returned Simplex_handle + std::cout << "vertex = " << vertex << " | vector[" << position << "] = " << SimplexVector6[position] << std::endl; + BOOST_CHECK(vertex == SimplexVector6[position]); + position++; + } + /* Inserted simplex: */ /* 1 6 */ /* o---o */ @@ -506,18 +498,17 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) typeSimplex simplexPair4 = std::make_pair(SimplexVector4, DEFAULT_FILTRATION_VALUE); typeSimplex simplexPair5 = std::make_pair(SimplexVector5, DEFAULT_FILTRATION_VALUE); typeSimplex simplexPair6 = std::make_pair(SimplexVector6, DEFAULT_FILTRATION_VALUE); - test_simplex_tree_contains(st,simplexPair1,6); // (2,1,0) is in position 6 - test_simplex_tree_contains(st,simplexPair2,7); // (3) is in position 7 - test_simplex_tree_contains(st,simplexPair3,8); // (3,0) is in position 8 - test_simplex_tree_contains(st,simplexPair4,2); // (1,0) is in position 2 - test_simplex_tree_contains(st,simplexPair5,14); // (3,4,5) is in position 14 - test_simplex_tree_contains(st,simplexPair6,26); // (7,6,1,0) is in position 26 - + test_simplex_tree_contains(st, simplexPair1, 6); // (2,1,0) is in position 6 + test_simplex_tree_contains(st, simplexPair2, 7); // (3) is in position 7 + test_simplex_tree_contains(st, simplexPair3, 8); // (3,0) is in position 8 + test_simplex_tree_contains(st, simplexPair4, 2); // (1,0) is in position 2 + test_simplex_tree_contains(st, simplexPair5, 14); // (3,4,5) is in position 14 + test_simplex_tree_contains(st, simplexPair6, 26); // (7,6,1,0) is in position 26 + // ------------------------------------------------------------------------------------------------------------------ // Find in the simplex_tree // ------------------------------------------------------------------------------------------------------------------ - typeVectorVertex simpleSimplexVector; - simpleSimplexVector.push_back(SECOND_VERTEX_HANDLE); + typeVectorVertex simpleSimplexVector{1}; Simplex_tree<>::Simplex_handle simplexFound = st.find(simpleSimplexVector); std::cout << "**************IS THE SIMPLEX {1} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -527,9 +518,7 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) // Check it is found BOOST_CHECK(simplexFound != st.null_simplex()); - Vertex_handle UNKNOWN_VERTEX_HANDLE = (Vertex_handle) 15; - typeVectorVertex unknownSimplexVector; - unknownSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); + typeVectorVertex unknownSimplexVector{15}; simplexFound = st.find(unknownSimplexVector); std::cout << "**************IS THE SIMPLEX {15} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -547,10 +536,8 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) std::cout << "***- NO IT ISN'T\n"; // Check it is found BOOST_CHECK(simplexFound != st.null_simplex()); - - typeVectorVertex otherSimplexVector; - otherSimplexVector.push_back(UNKNOWN_VERTEX_HANDLE); - otherSimplexVector.push_back(SECOND_VERTEX_HANDLE); + + typeVectorVertex otherSimplexVector{1, 15}; simplexFound = st.find(otherSimplexVector); std::cout << "**************IS THE SIMPLEX {15,1} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -560,10 +547,7 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) // Check it is NOT found BOOST_CHECK(simplexFound == st.null_simplex()); - typeVectorVertex invSimplexVector; - invSimplexVector.push_back(SECOND_VERTEX_HANDLE); - invSimplexVector.push_back(THIRD_VERTEX_HANDLE); - invSimplexVector.push_back(FIRST_VERTEX_HANDLE); + typeVectorVertex invSimplexVector{1, 2, 0}; simplexFound = st.find(invSimplexVector); std::cout << "**************IS THE SIMPLEX {1,2,0} IN THE SIMPLEX TREE ?\n"; if (simplexFound != st.null_simplex()) @@ -572,19 +556,191 @@ BOOST_AUTO_TEST_CASE( NSimplexAndSubfaces_tree_insertion ) std::cout << "***- NO IT ISN'T\n"; // Check it is found BOOST_CHECK(simplexFound != st.null_simplex()); - + // Display the Simplex_tree - Can not be done in the middle of 2 inserts std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; std::cout << " - dimension " << st.dimension() << " - filtration " << st.filtration() << std::endl; std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; - for( auto f_simplex : st.filtration_simplex_range() ) - { + for (auto f_simplex : st.filtration_simplex_range()) { std::cout << " " << "[" << st.filtration(f_simplex) << "] "; - for( auto vertex : st.simplex_vertex_range(f_simplex) ) - { - std::cout << (int)vertex << " "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; + } + std::cout << std::endl; + } +} + +void test_cofaces(typeST& st, std::vector<Vertex_handle> expected, int dim, std::vector<typeST::Simplex_handle> res) { + typeST::Cofaces_simplex_range cofaces; + if (dim == 0) + cofaces = st.star_simplex_range(st.find(expected)); + else + cofaces = st.cofaces_simplex_range(st.find(expected), dim); + for (auto simplex = cofaces.begin(); simplex != cofaces.end(); ++simplex) { + typeST::Simplex_vertex_range rg = st.simplex_vertex_range(*simplex); + for (auto vertex = rg.begin(); vertex != rg.end(); ++vertex) { + std::cout << "(" << *vertex << ")"; } std::cout << std::endl; + BOOST_CHECK(std::find(res.begin(), res.end(), *simplex) != res.end()); } +} + +BOOST_AUTO_TEST_CASE(coface_on_simplex_tree) { + std::cout << "********************************************************************" << std::endl; + std::cout << "TEST COFACE ALGORITHM" << std::endl; + typeST st; + + typeVectorVertex SimplexVector{2, 1, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + SimplexVector = {3, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {3, 4, 5}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {0, 1, 6, 7}; + st.insert_simplex_and_subfaces(SimplexVector); + + /* Inserted simplex: */ + /* 1 6 */ + /* o---o */ + /* /X\7/ */ + /* o---o---o---o */ + /* 2 0 3\X/4 */ + /* o */ + /* 5 */ + + // FIXME + st.set_dimension(3); + + std::vector<Vertex_handle> simplex_result; + std::vector<typeST::Simplex_handle> result; + std::cout << "First test - Star of (3):" << std::endl; + + simplex_result = {3}; + result.push_back(st.find(simplex_result)); + + simplex_result = {3, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {4, 3}; + result.push_back(st.find(simplex_result)); + + simplex_result = {5, 4, 3}; + result.push_back(st.find(simplex_result)); + + simplex_result = {5, 3}; + result.push_back(st.find(simplex_result)); + simplex_result.clear(); + + std::vector<Vertex_handle> vertex = {3}; + test_cofaces(st, vertex, 0, result); + vertex.clear(); + result.clear(); + + vertex.push_back(1); + vertex.push_back(7); + std::cout << "Second test - Star of (1,7): " << std::endl; + + simplex_result = {7, 1}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 6, 1, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 1, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 6, 1}; + result.push_back(st.find(simplex_result)); + + test_cofaces(st, vertex, 0, result); + result.clear(); + + std::cout << "Third test - 2-dimension Cofaces of simplex(1,7) : " << std::endl; + + simplex_result = {7, 1, 0}; + result.push_back(st.find(simplex_result)); + + simplex_result = {7, 6, 1}; + result.push_back(st.find(simplex_result)); + + test_cofaces(st, vertex, 1, result); + result.clear(); + + std::cout << "Cofaces with a codimension too high (codimension + vetices > tree.dimension) :" << std::endl; + test_cofaces(st, vertex, 5, result); + + //std::cout << "Cofaces with an empty codimension" << std::endl; + //test_cofaces(st, vertex, -1, result); + // std::cout << "Cofaces in an empty simplex tree" << std::endl; + // typeST empty_tree; + // test_cofaces(empty_tree, vertex, 1, result); + //std::cout << "Cofaces of an empty simplex" << std::endl; + //vertex.clear(); + // test_cofaces(st, vertex, 1, result); + +} + +BOOST_AUTO_TEST_CASE(copy_move_on_simplex_tree) { + std::cout << "********************************************************************" << std::endl; + std::cout << "TEST COPY MOVE CONSTRUCTORS" << std::endl; + typeST st; + + typeVectorVertex SimplexVector{2, 1, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {3, 0}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {3, 4, 5}; + st.insert_simplex_and_subfaces(SimplexVector); + + SimplexVector = {0, 1, 6, 7}; + st.insert_simplex_and_subfaces(SimplexVector); + + /* Inserted simplex: */ + /* 1 6 */ + /* o---o */ + /* /X\7/ */ + /* o---o---o---o */ + /* 2 0 3\X/4 */ + /* o */ + /* 5 */ + + // FIXME + st.set_dimension(3); + + std::cout << "Printing st - address = " << &st << std::endl; + + // Copy constructor + typeST st_copy = st; + std::cout << "Printing a copy of st - address = " << &st_copy << std::endl; + + // Check the data are the same + BOOST_CHECK(st == st_copy); + // Check there is a new simplex tree reference + BOOST_CHECK(&st != &st_copy); + + // Move constructor + typeST st_move = std::move(st); + std::cout << "Printing a move of st - address = " << &st_move << std::endl; + + // Check the data are the same + BOOST_CHECK(st_move == st_copy); + // Check there is a new simplex tree reference + BOOST_CHECK(&st_move != &st_copy); + BOOST_CHECK(&st_move != &st); + + typeST st_empty; + // Check st has been emptied by the move + BOOST_CHECK(st == st_empty); + BOOST_CHECK(st.filtration() == 0); + BOOST_CHECK(st.dimension() == -1); + BOOST_CHECK(st.num_simplices() == 0); + BOOST_CHECK(st.num_vertices() == (size_t)0); + + std::cout << "Printing st once again- address = " << &st << std::endl; } |