diff options
Diffstat (limited to 'src')
52 files changed, 1749 insertions, 556 deletions
diff --git a/src/Alpha_complex/include/gudhi/Alpha_complex.h b/src/Alpha_complex/include/gudhi/Alpha_complex.h index 1ff95c3d..5f7d7622 100644 --- a/src/Alpha_complex/include/gudhi/Alpha_complex.h +++ b/src/Alpha_complex/include/gudhi/Alpha_complex.h @@ -268,8 +268,6 @@ class Alpha_complex { return false; // ----- >> } - complex.set_dimension(triangulation_->maximal_dimension()); - // -------------------------------------------------------------------------------------------- // Simplex_tree construction from loop on triangulation finite full cells list if (triangulation_->number_of_vertices() > 0) { diff --git a/src/Alpha_complex/test/Alpha_complex_unit_test.cpp b/src/Alpha_complex/test/Alpha_complex_unit_test.cpp index 7380547f..166373fe 100644 --- a/src/Alpha_complex/test/Alpha_complex_unit_test.cpp +++ b/src/Alpha_complex/test/Alpha_complex_unit_test.cpp @@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(Alpha_complex_from_points) { BOOST_CHECK(simplex_tree.num_simplices() == 15); std::cout << "simplex_tree.dimension()=" << simplex_tree.dimension() << std::endl; - BOOST_CHECK(simplex_tree.dimension() == 4); + BOOST_CHECK(simplex_tree.dimension() == 3); std::cout << "simplex_tree.num_vertices()=" << simplex_tree.num_vertices() << std::endl; BOOST_CHECK(simplex_tree.num_vertices() == 4); @@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(Alpha_complex_from_points) { BOOST_CHECK(simplex_tree.num_simplices() == 10); std::cout << "simplex_tree.dimension()=" << simplex_tree.dimension() << std::endl; - BOOST_CHECK(simplex_tree.dimension() == 4); + BOOST_CHECK(simplex_tree.dimension() == 1); std::cout << "simplex_tree.num_vertices()=" << simplex_tree.num_vertices() << std::endl; BOOST_CHECK(simplex_tree.num_vertices() == 4); diff --git a/src/Doxyfile b/src/Doxyfile index 7f5975eb..0ef81e5c 100644 --- a/src/Doxyfile +++ b/src/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "GUDHI" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "2.0.1-rc2" +PROJECT_NUMBER = "2.0.1" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/src/Persistent_cohomology/doc/Intro_persistent_cohomology.h b/src/Persistent_cohomology/doc/Intro_persistent_cohomology.h index ece5e6c3..1b8ff95a 100644 --- a/src/Persistent_cohomology/doc/Intro_persistent_cohomology.h +++ b/src/Persistent_cohomology/doc/Intro_persistent_cohomology.h @@ -202,10 +202,10 @@ and a weights file. \code $> ./weighted_alpha_complex_3d_persistence ../../data/points/tore3D_300.off ../../data/points/tore3D_300.weights 2 0.45 \endcode \code Simplex_tree dim: 3 -2 -0 0 inf -2 1 0.0682162 1.0001 -2 1 0.0934117 1.00003 -2 2 0.56444 1.03938 \endcode +2 0 -1 inf +2 1 -0.931784 0.000103311 +2 1 -0.906588 2.60165e-05 +2 2 -0.43556 0.0393798 \endcode \li <a href="_persistent_cohomology_2alpha_complex_persistence_8cpp-example.html"> Persistent_cohomology/alpha_complex_persistence.cpp</a> computes the persistent homology with @@ -221,7 +221,8 @@ Simplex_tree dim: 3 \li <a href="_persistent_cohomology_2periodic_alpha_complex_3d_persistence_8cpp-example.html"> Persistent_cohomology/periodic_alpha_complex_3d_persistence.cpp</a> computes the persistent homology with \f$\mathbb{Z}/2\mathbb{Z}\f$ coefficients of the periodic alpha complex on points sampling from an OFF file. -\code $> ./periodic_alpha_complex_3d_persistence ../../data/points/grid_10_10_10_in_0_1.off 3 1.0 \endcode +\code $> ./periodic_alpha_complex_3d_persistence ../../data/points/grid_10_10_10_in_0_1.off +../../data/points/iso_cuboid_3_in_0_1.txt 3 1.0 \endcode \code Periodic Delaunay computed. Simplex_tree dim: 3 3 0 0 inf diff --git a/src/Persistent_cohomology/example/CMakeLists.txt b/src/Persistent_cohomology/example/CMakeLists.txt index 926cef6b..80e5647d 100644 --- a/src/Persistent_cohomology/example/CMakeLists.txt +++ b/src/Persistent_cohomology/example/CMakeLists.txt @@ -39,8 +39,8 @@ add_test(NAME Persistent_cohomology_example_from_simple_simplex_tree COMMAND $<T "1" "0") add_test(NAME Persistent_cohomology_example_from_rips_distance_matrix COMMAND $<TARGET_FILE:rips_distance_matrix_persistence> "${CMAKE_SOURCE_DIR}/data/distance_matrix/full_square_distance_matrix.csv" "-r" "1.0" "-d" "3" "-p" "3" "-m" "0") -add_test(rips_distance_matrix ${CMAKE_CURRENT_BINARY_DIR}/rips_distance_matrix_persistence - ${CMAKE_SOURCE_DIR}/data/correlation_matrix/full_correlation_matrix.csv.csv -r 1.0 -d 3 -p 3 -m 0) +add_test(NAME Persistent_cohomology_example_from_rips_correlation_matrix COMMAND $<TARGET_FILE:rips_correlation_matrix_persistence> + "${CMAKE_SOURCE_DIR}/data/correlation_matrix/lower_triangular_correlation_matrix.csv" "-c" "0.3" "-d" "3" "-p" "3" "-m" "0") add_test(NAME Persistent_cohomology_example_from_rips_on_tore_3D COMMAND $<TARGET_FILE:rips_persistence> "${CMAKE_SOURCE_DIR}/data/points/tore3D_1307.off" "-r" "0.25" "-m" "0.5" "-d" "3" "-p" "3") add_test(NAME Persistent_cohomology_example_from_rips_step_by_step_on_tore_3D COMMAND $<TARGET_FILE:rips_persistence_step_by_step> @@ -55,6 +55,7 @@ add_test(NAME Persistent_cohomology_example_from_file_3_3_100 COMMAND $<TARGET_F install(TARGETS plain_homology DESTINATION bin) install(TARGETS persistence_from_simple_simplex_tree DESTINATION bin) install(TARGETS rips_distance_matrix_persistence DESTINATION bin) +install(TARGETS rips_correlation_matrix_persistence DESTINATION bin) install(TARGETS rips_persistence DESTINATION bin) install(TARGETS rips_persistence_step_by_step DESTINATION bin) install(TARGETS rips_persistence_via_boundary_matrix DESTINATION bin) @@ -79,24 +80,18 @@ if(CGAL_FOUND) target_link_libraries(alpha_complex_3d_persistence ${CGAL_LIBRARY}) add_executable(exact_alpha_complex_3d_persistence exact_alpha_complex_3d_persistence.cpp) target_link_libraries(exact_alpha_complex_3d_persistence ${CGAL_LIBRARY}) - add_executable(weighted_alpha_complex_3d_persistence weighted_alpha_complex_3d_persistence.cpp) - target_link_libraries(weighted_alpha_complex_3d_persistence ${CGAL_LIBRARY}) if (TBB_FOUND) target_link_libraries(alpha_complex_3d_persistence ${TBB_LIBRARIES}) target_link_libraries(exact_alpha_complex_3d_persistence ${TBB_LIBRARIES}) - target_link_libraries(weighted_alpha_complex_3d_persistence ${TBB_LIBRARIES}) endif(TBB_FOUND) add_test(NAME Persistent_cohomology_example_alpha_complex_3d COMMAND $<TARGET_FILE:alpha_complex_3d_persistence> "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "2" "0.45") add_test(NAME Persistent_cohomology_example_exact_alpha_complex_3d COMMAND $<TARGET_FILE:exact_alpha_complex_3d_persistence> "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "2" "0.45") - add_test(NAME Persistent_cohomology_example_weighted_alpha_complex_3d COMMAND $<TARGET_FILE:weighted_alpha_complex_3d_persistence> - "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.weights" "2" "0.45") install(TARGETS alpha_complex_3d_persistence DESTINATION bin) install(TARGETS exact_alpha_complex_3d_persistence DESTINATION bin) - install(TARGETS weighted_alpha_complex_3d_persistence DESTINATION bin) if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) add_executable (alpha_complex_persistence alpha_complex_persistence.cpp) @@ -117,7 +112,7 @@ if(CGAL_FOUND) add_test(NAME Persistent_cohomology_example_alpha_complex COMMAND $<TARGET_FILE:alpha_complex_persistence> "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "-p" "2" "-m" "0.45") add_test(NAME Persistent_cohomology_example_periodic_alpha_complex_3d COMMAND $<TARGET_FILE:periodic_alpha_complex_3d_persistence> - "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off" "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt" "2" "0") + "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off" "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt" "3" "1.0") add_test(NAME Persistent_cohomology_example_custom_persistence_sort COMMAND $<TARGET_FILE:custom_persistence_sort>) install(TARGETS alpha_complex_persistence DESTINATION bin) @@ -125,4 +120,31 @@ if(CGAL_FOUND) install(TARGETS custom_persistence_sort DESTINATION bin) endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) + + if (NOT CGAL_VERSION VERSION_LESS 4.11.0) + add_executable(weighted_periodic_alpha_complex_3d_persistence weighted_periodic_alpha_complex_3d_persistence.cpp) + target_link_libraries(weighted_periodic_alpha_complex_3d_persistence ${CGAL_LIBRARY}) + if (TBB_FOUND) + target_link_libraries(weighted_periodic_alpha_complex_3d_persistence ${TBB_LIBRARIES}) + endif(TBB_FOUND) + + add_test(NAME Persistent_cohomology_example_weigted_periodic_alpha_complex_3d COMMAND $<TARGET_FILE:weighted_periodic_alpha_complex_3d_persistence> + "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.off" "${CMAKE_SOURCE_DIR}/data/points/grid_10_10_10_in_0_1.weights" + "${CMAKE_SOURCE_DIR}/data/points/iso_cuboid_3_in_0_1.txt" "3" "1.0") + + install(TARGETS weighted_periodic_alpha_complex_3d_persistence DESTINATION bin) + + endif (NOT CGAL_VERSION VERSION_LESS 4.11.0) + + add_executable(weighted_alpha_complex_3d_persistence weighted_alpha_complex_3d_persistence.cpp) + target_link_libraries(weighted_alpha_complex_3d_persistence ${CGAL_LIBRARY}) + if (TBB_FOUND) + target_link_libraries(weighted_alpha_complex_3d_persistence ${TBB_LIBRARIES}) + endif(TBB_FOUND) + + install(TARGETS weighted_alpha_complex_3d_persistence DESTINATION bin) + + add_test(NAME Persistent_cohomology_example_weighted_alpha_complex_3d COMMAND $<TARGET_FILE:weighted_alpha_complex_3d_persistence> + "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.weights" "2" "0.45") + endif(CGAL_FOUND) diff --git a/src/Persistent_cohomology/example/alpha_complex_3d_helper.h b/src/Persistent_cohomology/example/alpha_complex_3d_helper.h index 7865e4ec..6b3b7d5d 100644 --- a/src/Persistent_cohomology/example/alpha_complex_3d_helper.h +++ b/src/Persistent_cohomology/example/alpha_complex_3d_helper.h @@ -23,7 +23,7 @@ #ifndef ALPHA_COMPLEX_3D_HELPER_H_ #define ALPHA_COMPLEX_3D_HELPER_H_ -template<class Vertex_list, class Cell_handle> +template <class Vertex_list, class Cell_handle> Vertex_list from_cell(const Cell_handle& ch) { Vertex_list the_list; for (auto i = 0; i < 4; i++) { @@ -35,7 +35,7 @@ Vertex_list from_cell(const Cell_handle& ch) { return the_list; } -template<class Vertex_list, class Facet> +template <class Vertex_list, class Facet> Vertex_list from_facet(const Facet& fct) { Vertex_list the_list; for (auto i = 0; i < 4; i++) { @@ -49,7 +49,7 @@ Vertex_list from_facet(const Facet& fct) { return the_list; } -template<class Vertex_list, class Edge_3> +template <class Vertex_list, class Edge_3> Vertex_list from_edge(const Edge_3& edg) { Vertex_list the_list; for (auto i = 0; i < 4; i++) { @@ -63,7 +63,7 @@ Vertex_list from_edge(const Edge_3& edg) { return the_list; } -template<class Vertex_list, class Vertex_handle> +template <class Vertex_list, class Vertex_handle> Vertex_list from_vertex(const Vertex_handle& vh) { Vertex_list the_list; #ifdef DEBUG_TRACES diff --git a/src/Persistent_cohomology/example/alpha_complex_3d_persistence.cpp b/src/Persistent_cohomology/example/alpha_complex_3d_persistence.cpp index f63ff0f6..26196a6f 100644 --- a/src/Persistent_cohomology/example/alpha_complex_3d_persistence.cpp +++ b/src/Persistent_cohomology/example/alpha_complex_3d_persistence.cpp @@ -39,6 +39,7 @@ #include <utility> #include <list> #include <vector> +#include <cstdlib> #include "alpha_complex_3d_helper.h" @@ -56,10 +57,10 @@ using Point_3 = Kernel::Point_3; // filtration with alpha values needed type definition using Alpha_value_type = Alpha_shape_3::FT; using Object = CGAL::Object; -using Dispatch = 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> > > >; +using Dispatch = + 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> > > >; using Cell_handle = Alpha_shape_3::Cell_handle; using Facet = Alpha_shape_3::Facet; using Edge_3 = Alpha_shape_3::Edge; @@ -70,19 +71,19 @@ using Vertex_list = std::list<Alpha_shape_3::Vertex_handle>; using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>; using Filtration_value = ST::Filtration_value; using Simplex_tree_vertex = ST::Vertex_handle; -using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex >; +using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; using Alpha_shape_simplex_tree_pair = std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; -using Simplex_tree_vector_vertex = std::vector< Simplex_tree_vertex >; -using PCOH = Gudhi::persistent_cohomology::Persistent_cohomology< ST, Gudhi::persistent_cohomology::Field_Zp >; +using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>; +using Persistent_cohomology = + Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>; void usage(const std::string& progName) { - std::cerr << "Usage:\n" << progName << " path_to_OFF_file coeff_field_characteristic[integer " << - "> 0] min_persistence[float >= -1.0]\n"; - std::cerr << " path_to_OFF_file is the path to your points cloud in OFF format.\n"; + std::cerr << "Usage: " << progName + << " path_to_the_OFF_file coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; exit(-1); } -int main(int argc, char * const argv[]) { +int main(int argc, char* const argv[]) { // program args management if (argc != 4) { std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; @@ -90,13 +91,7 @@ int main(int argc, char * const argv[]) { } int coeff_field_characteristic = atoi(argv[2]); - - Filtration_value min_persistence = 0.0; - int returnedScanValue = sscanf(argv[3], "%f", &min_persistence); - if ((returnedScanValue == EOF) || (min_persistence < -1.0)) { - std::cerr << "Error: " << argv[3] << " is not correct\n"; - usage(argv[0]); - } + Filtration_value min_persistence = strtof(argv[3], nullptr); // Read points from file std::string offInputFile(argv[1]); @@ -143,28 +138,28 @@ int main(int argc, char * const argv[]) { Filtration_value filtration_max = 0.0; 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)) { + if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { vertex_list = from_cell<Vertex_list, Cell_handle>(*cell); count_cells++; if (dim_max < 3) { // Cell is of dim 3 dim_max = 3; } - } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { + } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) { vertex_list = from_facet<Vertex_list, Facet>(*facet); count_facets++; if (dim_max < 2) { // Facet is of dim 2 dim_max = 2; } - } else if (const Edge_3 * edge = CGAL::object_cast<Edge_3>(&object_iterator)) { + } else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) { vertex_list = from_edge<Vertex_list, Edge_3>(*edge); count_edges++; if (dim_max < 1) { // Edge_3 is of dim 1 dim_max = 1; } - } else if (const Vertex_handle * vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { + } else if (const Vertex_handle* vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { count_vertices++; vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex); } @@ -203,7 +198,6 @@ int main(int argc, char * const argv[]) { else std::cout << "This shall not happen" << std::endl; } - simplex_tree.set_dimension(dim_max); #ifdef DEBUG_TRACES std::cout << "vertices \t\t" << count_vertices << std::endl; @@ -211,7 +205,6 @@ int main(int argc, char * const argv[]) { 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; @@ -230,7 +223,7 @@ int main(int argc, char * const argv[]) { std::cout << "Simplex_tree dim: " << simplex_tree.dimension() << std::endl; // Compute the persistence diagram of the complex - PCOH pcoh(simplex_tree); + Persistent_cohomology pcoh(simplex_tree, true); // initializes the coefficient field for homology pcoh.init_coefficients(coeff_field_characteristic); diff --git a/src/Persistent_cohomology/example/exact_alpha_complex_3d_persistence.cpp b/src/Persistent_cohomology/example/exact_alpha_complex_3d_persistence.cpp index 09561d03..2e2bfd2f 100644 --- a/src/Persistent_cohomology/example/exact_alpha_complex_3d_persistence.cpp +++ b/src/Persistent_cohomology/example/exact_alpha_complex_3d_persistence.cpp @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2014 INRIA Saclay (France) + * Copyright (C) 2014 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,6 +39,7 @@ #include <utility> #include <list> #include <vector> +#include <cstdlib> #include "alpha_complex_3d_helper.h" @@ -57,10 +58,10 @@ using Point_3 = Kernel::Point_3; // filtration with alpha values needed type definition using Alpha_value_type = Alpha_shape_3::FT; using Object = CGAL::Object; -using Dispatch = 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> > > >; +using Dispatch = + 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> > > >; using Cell_handle = Alpha_shape_3::Cell_handle; using Facet = Alpha_shape_3::Facet; using Edge_3 = Alpha_shape_3::Edge; @@ -71,19 +72,19 @@ using Vertex_list = std::list<Vertex_handle>; using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>; using Filtration_value = ST::Filtration_value; using Simplex_tree_vertex = ST::Vertex_handle; -using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex >; +using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; using Alpha_shape_simplex_tree_pair = std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; -using Simplex_tree_vector_vertex = std::vector< Simplex_tree_vertex >; -using PCOH = Gudhi::persistent_cohomology::Persistent_cohomology< ST, Gudhi::persistent_cohomology::Field_Zp >; +using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>; +using Persistent_cohomology = + Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>; -void usage(char * const progName) { - std::cerr << "Usage:\n" << progName << " path_to_OFF_file coeff_field_characteristic[integer " << - "> 0] min_persistence[float >= -1.0]\n"; - std::cerr << " path_to_OFF_file is the path to your points cloud in OFF format.\n"; +void usage(const std::string& progName) { + std::cerr << "Usage: " << progName + << " path_to_the_OFF_file coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; exit(-1); } -int main(int argc, char * const argv[]) { +int main(int argc, char* const argv[]) { // program args management if (argc != 4) { std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; @@ -91,13 +92,7 @@ int main(int argc, char * const argv[]) { } int coeff_field_characteristic = atoi(argv[2]); - - Filtration_value min_persistence = 0.0; - int returnedScanValue = sscanf(argv[3], "%f", &min_persistence); - if ((returnedScanValue == EOF) || (min_persistence < -1.0)) { - std::cerr << "Error: " << argv[3] << " is not correct\n"; - usage(argv[0]); - } + Filtration_value min_persistence = strtof(argv[3], nullptr); // Read points from file std::string offInputFile(argv[1]); @@ -144,28 +139,28 @@ int main(int argc, char * const argv[]) { Filtration_value filtration_max = 0.0; 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)) { + if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { vertex_list = from_cell<Vertex_list, Cell_handle>(*cell); count_cells++; if (dim_max < 3) { // Cell is of dim 3 dim_max = 3; } - } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { + } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) { vertex_list = from_facet<Vertex_list, Facet>(*facet); count_facets++; if (dim_max < 2) { // Facet is of dim 2 dim_max = 2; } - } else if (const Edge_3 * edge = CGAL::object_cast<Edge_3>(&object_iterator)) { + } else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) { vertex_list = from_edge<Vertex_list, Edge_3>(*edge); count_edges++; if (dim_max < 1) { // Edge_3 is of dim 1 dim_max = 1; } - } else if (const Vertex_handle * vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { + } else if (const Vertex_handle* vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { count_vertices++; vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex); } @@ -205,7 +200,6 @@ int main(int argc, char * const argv[]) { else std::cout << "This shall not happen" << std::endl; } - simplex_tree.set_dimension(dim_max); #ifdef DEBUG_TRACES std::cout << "vertices \t\t" << count_vertices << std::endl; @@ -213,7 +207,6 @@ int main(int argc, char * const argv[]) { 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; @@ -232,7 +225,7 @@ int main(int argc, char * const argv[]) { std::cout << "Simplex_tree dim: " << simplex_tree.dimension() << std::endl; // Compute the persistence diagram of the complex - PCOH pcoh(simplex_tree); + Persistent_cohomology pcoh(simplex_tree, true); // initializes the coefficient field for homology pcoh.init_coefficients(coeff_field_characteristic); diff --git a/src/Persistent_cohomology/example/periodic_alpha_complex_3d_persistence.cpp b/src/Persistent_cohomology/example/periodic_alpha_complex_3d_persistence.cpp index 8140a3c5..c6d3e236 100644 --- a/src/Persistent_cohomology/example/periodic_alpha_complex_3d_persistence.cpp +++ b/src/Persistent_cohomology/example/periodic_alpha_complex_3d_persistence.cpp @@ -63,10 +63,10 @@ using Point_3 = PK::Point_3; // filtration with alpha values needed type definition using Alpha_value_type = Alpha_shape_3::FT; using Object = CGAL::Object; -using Dispatch = 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> > > >; +using Dispatch = + 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> > > >; using Cell_handle = Alpha_shape_3::Cell_handle; using Facet = Alpha_shape_3::Facet; using Edge_3 = Alpha_shape_3::Edge; @@ -77,27 +77,19 @@ using Vertex_list = std::list<Alpha_shape_3::Vertex_handle>; using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>; using Filtration_value = ST::Filtration_value; using Simplex_tree_vertex = ST::Vertex_handle; -using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex >; +using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; using Alpha_shape_simplex_tree_pair = std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; -using Simplex_tree_vector_vertex = std::vector< Simplex_tree_vertex >; -using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology< - ST, Gudhi::persistent_cohomology::Field_Zp >; - -void usage(char * const progName) { - std::cerr << "Usage:\n" << progName << " path_to_OFF_file path_to_iso_cuboid_3_file coeff_field_characteristic[" << - "integer > 0] min_persistence[float >= -1.0]\n" << - " path_to_OFF_file is the path to your points cloud in OFF format.\n" << - " path_to_iso_cuboid_3_file is the path to the iso cuboid file with the following format :\n" << - " x_min y_min z_min x_max y_max z_max\n" << - " In this example, the periodic cube will be " << - "{ x = [x_min,x_max]; y = [y_min,y_max]; z = [z_min,z_max] }.\n" << - " For more information, please refer to\n" << - " https://doc.cgal.org/latest/Kernel_23/classCGAL_1_1Iso__cuboid__3.html\n"; +using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>; +using Persistent_cohomology = + Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>; +void usage(const std::string& progName) { + std::cerr << "Usage: " << progName << " path_to_the_OFF_file path_to_iso_cuboid_3_file " + "coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; exit(-1); } -int main(int argc, char * const argv[]) { +int main(int argc, char* const argv[]) { // program args management if (argc != 5) { std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; @@ -168,29 +160,28 @@ int main(int argc, char * const argv[]) { Filtration_value filtration_max = 0.0; 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)) { + if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { vertex_list = from_cell<Vertex_list, Cell_handle>(*cell); count_cells++; if (dim_max < 3) { // Cell is of dim 3 dim_max = 3; } - } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { + } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) { vertex_list = from_facet<Vertex_list, Facet>(*facet); count_facets++; if (dim_max < 2) { // Facet is of dim 2 dim_max = 2; } - } else if (const Edge_3 * edge = CGAL::object_cast<Edge_3>(&object_iterator)) { + } else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) { vertex_list = from_edge<Vertex_list, Edge_3>(*edge); count_edges++; if (dim_max < 1) { // Edge_3 is of dim 1 dim_max = 1; } - } else if (const Alpha_shape_3::Vertex_handle * vertex = - CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) { + } else if (const Vertex_handle* vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { count_vertices++; vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex); } @@ -216,7 +207,7 @@ int main(int argc, char * const argv[]) { } } // Construction of the simplex_tree - Filtration_value filtr = /*std::sqrt*/(*the_alpha_value_iterator); + Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator); #ifdef DEBUG_TRACES std::cout << "filtration = " << filtr << std::endl; #endif // DEBUG_TRACES @@ -229,7 +220,6 @@ int main(int argc, char * const argv[]) { else std::cout << "This shall not happen" << std::endl; } - simplex_tree.set_dimension(dim_max); #ifdef DEBUG_TRACES std::cout << "vertices \t\t" << count_vertices << std::endl; @@ -237,7 +227,6 @@ int main(int argc, char * const argv[]) { 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; diff --git a/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp b/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp index 8214d66a..8ef479d4 100644 --- a/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp +++ b/src/Persistent_cohomology/example/persistence_from_simple_simplex_tree.cpp @@ -142,7 +142,6 @@ int main(int argc, char * const argv[]) { /* An edge [11,6] */ /* An edge [10,12,2] */ - st.set_dimension(2); std::cout << "The complex contains " << st.num_simplices() << " simplices - " << st.num_vertices() << " vertices " << std::endl; diff --git a/src/Persistent_cohomology/example/plain_homology.cpp b/src/Persistent_cohomology/example/plain_homology.cpp index 50f692f2..a5ae09c8 100644 --- a/src/Persistent_cohomology/example/plain_homology.cpp +++ b/src/Persistent_cohomology/example/plain_homology.cpp @@ -64,8 +64,6 @@ int main() { st.insert_simplex_and_subfaces(edge03); st.insert_simplex(edge13); st.insert_simplex(vertex4); - // FIXME: Remove this line - st.set_dimension(2); // Sort the simplices in the order of the filtration st.initialize_filtration(); diff --git a/src/Persistent_cohomology/example/rips_correlation_matrix_persistence.cpp b/src/Persistent_cohomology/example/rips_correlation_matrix_persistence.cpp index 6f12dada..94d5b8d4 100644 --- a/src/Persistent_cohomology/example/rips_correlation_matrix_persistence.cpp +++ b/src/Persistent_cohomology/example/rips_correlation_matrix_persistence.cpp @@ -68,8 +68,8 @@ int main(int argc, char* argv[]) { } } - //If the treshold, being minimal corelation is in the range [0,1], - //change it to 1-threshold + // If the threshold, being minimal correlation is in the range [0,1], + // change it to 1-threshold if ( ( threshold>=0 ) && ( threshold<=1 ) ) { threshold = 1-threshold; @@ -95,7 +95,7 @@ int main(int argc, char* argv[]) { pcoh.compute_persistent_cohomology(min_persistence); - //invert the persistence diagram + // invert the persistence diagram auto pairs = pcoh.get_persistent_pairs(); std::vector< intervals_common > processed_persistence_intervals; processed_persistence_intervals.reserve( pairs.size() ); @@ -128,34 +128,34 @@ void program_options(int argc, char* argv[], std::string& csv_matrix_file, std:: Filtration_value& threshold, int& dim_max, int& p, Filtration_value& min_persistence) { namespace po = boost::program_options; po::options_description hidden("Hidden options"); - hidden.add_options()( - "input-file", po::value<std::string>(&csv_matrix_file), - "Name of file containing a distance matrix. Can be square or lower triangular matrix. Separator is ';'."); + // hidden.add_options()( + // "input-file", po::value<std::string>(&csv_matrix_file), + // "Name of file containing a correlation matrix. Can be square or lower triangular matrix. Separator is ';'."); hidden.add_options() ("input-file", po::value<std::string>(&csv_matrix_file), - "Name of file containing a corelation matrix. Can be square or lower triangular matrix. Separator is ';'."); + "Name of file containing a correlation matrix. Can be square or lower triangular matrix. Separator is ';'."); po::options_description visible("Allowed options", 100); - visible.add_options()("help,h", "produce help message")( - "output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), - "Name of file in which the persistence diagram is written. Default print in std::cout")( - "max-edge-length,r", - po::value<Filtration_value>(&threshold)->default_value(std::numeric_limits<Filtration_value>::infinity()), - "Maximal length of an edge for the Rips complex construction.")( - "cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), - "Maximal dimension of the Rips complex we want to compute.")( - "field-charac,p", po::value<int>(&p)->default_value(11), - "Characteristic p of the coefficient field Z/pZ for computing homology.")( - "min-persistence,m", po::value<Filtration_value>(&min_persistence), - "Minimal lifetime of homology feature to be recorded. Default is 0. Enter a negative value to see zero length " - "intervals"); + // visible.add_options()("help,h", "produce help message")( + // "output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), + // "Name of file in which the persistence diagram is written. Default print in std::cout")( + // "max-edge-length,r", + // po::value<Filtration_value>(&threshold)->default_value(std::numeric_limits<Filtration_value>::infinity()), + // "Maximal length of an edge for the Rips complex construction.")( + // "cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), + // "Maximal dimension of the Rips complex we want to compute.")( + // "field-charac,p", po::value<int>(&p)->default_value(11), + // "Characteristic p of the coefficient field Z/pZ for computing homology.")( + // "min-persistence,m", po::value<Filtration_value>(&min_persistence), + // "Minimal lifetime of homology feature to be recorded. Default is 0. Enter a negative value to see zero length " + // "intervals"); visible.add_options() ("help,h", "produce help message") ("output-file,o", po::value<std::string>(&filediag)->default_value(std::string()), "Name of file in which the persistence diagram is written. Default print in std::cout") - ("min-edge-corelation,c", + ("min-edge-correlation,c", po::value<Filtration_value>(&threshold)->default_value(std::numeric_limits<Filtration_value>::infinity()), - "Minimal corelation of an edge for the Rips complex construction.") + "Minimal correlation of an edge for the Rips complex construction.") ("cpx-dimension,d", po::value<int>(&dim_max)->default_value(1), "Maximal dimension of the Rips complex we want to compute.") ("field-charac,p", po::value<int>(&p)->default_value(11), @@ -176,7 +176,7 @@ void program_options(int argc, char* argv[], std::string& csv_matrix_file, std:: if (vm.count("help") || !vm.count("input-file")) { std::cout << std::endl; std::cout << "Compute the persistent homology with coefficient field Z/pZ \n"; - std::cout << "of a Rips complex defined on a corelation matrix.\n \n"; + std::cout << "of a Rips complex defined on a correlation matrix.\n \n"; std::cout << "The output diagram contains one bar per line, written with the convention: \n"; std::cout << " p dim b d \n"; std::cout << "where dim is the dimension of the homological feature,\n"; diff --git a/src/Persistent_cohomology/example/weighted_alpha_complex_3d_persistence.cpp b/src/Persistent_cohomology/example/weighted_alpha_complex_3d_persistence.cpp index 72268511..249a7ece 100644 --- a/src/Persistent_cohomology/example/weighted_alpha_complex_3d_persistence.cpp +++ b/src/Persistent_cohomology/example/weighted_alpha_complex_3d_persistence.cpp @@ -26,12 +26,17 @@ #include <gudhi/Persistent_cohomology.h> #include <gudhi/Points_3D_off_io.h> +#include <CGAL/config.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h> -#include <CGAL/Regular_triangulation_euclidean_traits_3.h> #include <CGAL/Regular_triangulation_3.h> #include <CGAL/Alpha_shape_3.h> #include <CGAL/iterator.h> +// For CGAL < 4.11 +#if CGAL_VERSION_NR < 1041100000 +#include <CGAL/Regular_triangulation_euclidean_traits_3.h> +#endif // CGAL_VERSION_NR < 1041100000 + #include <fstream> #include <cmath> #include <string> @@ -44,26 +49,44 @@ #include "alpha_complex_3d_helper.h" -// Traits +// Alpha_shape_3 templates type definitions using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; + +// For CGAL < 4.11 +#if CGAL_VERSION_NR < 1041100000 using Gt = CGAL::Regular_triangulation_euclidean_traits_3<Kernel>; using Vb = CGAL::Alpha_shape_vertex_base_3<Gt>; using Fb = CGAL::Alpha_shape_cell_base_3<Gt>; using Tds = CGAL::Triangulation_data_structure_3<Vb, Fb>; using Triangulation_3 = CGAL::Regular_triangulation_3<Gt, Tds>; -using Alpha_shape_3 = CGAL::Alpha_shape_3<Triangulation_3>; // From file type definition using Point_3 = Gt::Bare_point; using Weighted_point_3 = Gt::Weighted_point; +// For CGAL >= 4.11 +#else // CGAL_VERSION_NR < 1041100000 +using Rvb = CGAL::Regular_triangulation_vertex_base_3<Kernel>; +using Vb = CGAL::Alpha_shape_vertex_base_3<Kernel,Rvb>; +using Rcb = CGAL::Regular_triangulation_cell_base_3<Kernel>; +using Cb = CGAL::Alpha_shape_cell_base_3<Kernel,Rcb>; +using Tds = CGAL::Triangulation_data_structure_3<Vb,Cb>; +using Triangulation_3 = CGAL::Regular_triangulation_3<Kernel,Tds>; + +// From file type definition +using Point_3 = Triangulation_3::Bare_point; +using Weighted_point_3 = Triangulation_3::Weighted_point; +#endif // CGAL_VERSION_NR < 1041100000 + +using Alpha_shape_3 = CGAL::Alpha_shape_3<Triangulation_3>; + // filtration with alpha values needed type definition using Alpha_value_type = Alpha_shape_3::FT; using Object = CGAL::Object; -using Dispatch = 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> > > >; +using Dispatch = + 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> > > >; using Cell_handle = Alpha_shape_3::Cell_handle; using Facet = Alpha_shape_3::Facet; using Edge_3 = Alpha_shape_3::Edge; @@ -74,24 +97,19 @@ using Vertex_list = std::list<Alpha_shape_3::Vertex_handle>; using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>; using Filtration_value = ST::Filtration_value; using Simplex_tree_vertex = ST::Vertex_handle; -using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex >; +using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; using Alpha_shape_simplex_tree_pair = std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; -using Simplex_tree_vector_vertex = std::vector< Simplex_tree_vertex >; -using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology< - ST, Gudhi::persistent_cohomology::Field_Zp >; - -void usage(char * const progName) { - std::cerr << "Usage:\n" << progName << " path_to_OFF_file path_to_weight_file coeff_field_characteristic[integer " << - "> 0] min_persistence[float >= -1.0]\n"; - std::cerr << " path_to_OFF_file is the path to your points cloud in OFF format.\n"; - std::cerr << " path_to_weight_file is the path to the weights of your points cloud (one value per line.)\n"; - std::cerr << " Weights values are explained on CGAL documentation:\n"; - std::cerr << " https://doc.cgal.org/latest/Alpha_shapes_3/index.html#title0\n"; - std::cerr << " https://doc.cgal.org/latest/Triangulation_3/index.html#Triangulation3secclassRegulartriangulation\n"; +using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>; +using Persistent_cohomology = + Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>; + +void usage(const std::string& progName) { + std::cerr << "Usage: " << progName << " path_to_the_OFF_file path_to_weight_file coeff_field_characteristic[integer > " + "0] min_persistence[float >= -1.0]\n"; exit(-1); } -int main(int argc, char * const argv[]) { +int main(int argc, char* const argv[]) { // program args management if (argc != 5) { std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; @@ -167,29 +185,28 @@ int main(int argc, char * const argv[]) { Filtration_value filtration_max = 0.0; 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)) { + if (const Cell_handle* cell = CGAL::object_cast<Cell_handle>(&object_iterator)) { vertex_list = from_cell<Vertex_list, Cell_handle>(*cell); count_cells++; if (dim_max < 3) { // Cell is of dim 3 dim_max = 3; } - } else if (const Facet * facet = CGAL::object_cast<Facet>(&object_iterator)) { + } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) { vertex_list = from_facet<Vertex_list, Facet>(*facet); count_facets++; if (dim_max < 2) { // Facet is of dim 2 dim_max = 2; } - } else if (const Edge_3 * edge = CGAL::object_cast<Edge_3>(&object_iterator)) { + } else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) { vertex_list = from_edge<Vertex_list, Edge_3>(*edge); count_edges++; if (dim_max < 1) { // Edge_3 is of dim 1 dim_max = 1; } - } else if (const Alpha_shape_3::Vertex_handle * vertex = - CGAL::object_cast<Alpha_shape_3::Vertex_handle>(&object_iterator)) { + } else if (const Vertex_handle* vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { count_vertices++; vertex_list = from_vertex<Vertex_list, Vertex_handle>(*vertex); } @@ -215,7 +232,7 @@ int main(int argc, char * const argv[]) { } } // Construction of the simplex_tree - Filtration_value filtr = /*std::sqrt*/(*the_alpha_value_iterator); + Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator); #ifdef DEBUG_TRACES std::cout << "filtration = " << filtr << std::endl; #endif // DEBUG_TRACES @@ -228,7 +245,6 @@ int main(int argc, char * const argv[]) { else std::cout << "This shall not happen" << std::endl; } - simplex_tree.set_dimension(dim_max); #ifdef DEBUG_TRACES std::cout << "vertices \t\t" << count_vertices << std::endl; @@ -236,7 +252,6 @@ int main(int argc, char * const argv[]) { 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; diff --git a/src/Persistent_cohomology/example/weighted_periodic_alpha_complex_3d_persistence.cpp b/src/Persistent_cohomology/example/weighted_periodic_alpha_complex_3d_persistence.cpp new file mode 100644 index 00000000..13634ff7 --- /dev/null +++ b/src/Persistent_cohomology/example/weighted_periodic_alpha_complex_3d_persistence.cpp @@ -0,0 +1,281 @@ +/* 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 + * + * 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 <boost/variant.hpp> + +#include <gudhi/Simplex_tree.h> +#include <gudhi/Persistent_cohomology.h> +#include <gudhi/Points_3D_off_io.h> + +#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> +#include <CGAL/Periodic_3_regular_triangulation_traits_3.h> +#include <CGAL/Periodic_3_regular_triangulation_3.h> +#include <CGAL/Alpha_shape_3.h> +#include <CGAL/iterator.h> + +#include <fstream> +#include <cmath> +#include <string> +#include <tuple> +#include <map> +#include <utility> +#include <list> +#include <vector> +#include <cstdlib> + +#include "alpha_complex_3d_helper.h" + +// Traits +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using PK = CGAL::Periodic_3_regular_triangulation_traits_3<Kernel>; + +// Vertex type +using DsVb = CGAL::Periodic_3_triangulation_ds_vertex_base_3<>; +using Vb = CGAL::Regular_triangulation_vertex_base_3<PK,DsVb>; +using AsVb = CGAL::Alpha_shape_vertex_base_3<PK,Vb>; +// Cell type +using DsCb = CGAL::Periodic_3_triangulation_ds_cell_base_3<>; +using Cb = CGAL::Regular_triangulation_cell_base_3<PK,DsCb>; +using AsCb = CGAL::Alpha_shape_cell_base_3<PK,Cb>; +using Tds = CGAL::Triangulation_data_structure_3<AsVb,AsCb>; +using P3RT3 = CGAL::Periodic_3_regular_triangulation_3<PK,Tds>; +using Alpha_shape_3 = CGAL::Alpha_shape_3<P3RT3>; + +using Point_3 = P3RT3::Bare_point; +using Weighted_point_3 = P3RT3::Weighted_point; + +// filtration with alpha values needed type definition +using Alpha_value_type = Alpha_shape_3::FT; +using Object = CGAL::Object; +using Dispatch = + 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> > > >; +using Cell_handle = Alpha_shape_3::Cell_handle; +using Facet = Alpha_shape_3::Facet; +using Edge_3 = Alpha_shape_3::Edge; +using Vertex_handle = Alpha_shape_3::Vertex_handle; +using Vertex_list = std::list<Alpha_shape_3::Vertex_handle>; + +// gudhi type definition +using ST = Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_fast_persistence>; +using Filtration_value = ST::Filtration_value; +using Simplex_tree_vertex = ST::Vertex_handle; +using Alpha_shape_simplex_tree_map = std::map<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; +using Alpha_shape_simplex_tree_pair = std::pair<Alpha_shape_3::Vertex_handle, Simplex_tree_vertex>; +using Simplex_tree_vector_vertex = std::vector<Simplex_tree_vertex>; +using Persistent_cohomology = + Gudhi::persistent_cohomology::Persistent_cohomology<ST, Gudhi::persistent_cohomology::Field_Zp>; + +void usage(const std::string& progName) { + std::cerr << "Usage: " << progName << " path_to_the_OFF_file path_to_weight_file path_to_the_cuboid_file " + "coeff_field_characteristic[integer > 0] min_persistence[float >= -1.0]\n"; + exit(-1); +} + +int main(int argc, char* const argv[]) { + // program args management + if (argc != 6) { + std::cerr << "Error: Number of arguments (" << argc << ") is not correct\n"; + usage(argv[0]); + } + + int coeff_field_characteristic = atoi(argv[4]); + Filtration_value min_persistence = strtof(argv[5], nullptr); + + // Read points from file + std::string offInputFile(argv[1]); + // Read the OFF file (input file name given as parameter) and triangulate points + Gudhi::Points_3D_off_reader<Point_3> off_reader(offInputFile); + // Check the read operation was correct + if (!off_reader.is_valid()) { + std::cerr << "Unable to read file " << offInputFile << std::endl; + usage(argv[0]); + } + + // Retrieve the triangulation + std::vector<Point_3> lp = off_reader.get_point_cloud(); + + // Read weights information from file + std::ifstream weights_ifstr(argv[2]); + std::vector<Weighted_point_3> wp; + if (weights_ifstr.good()) { + double weight = 0.0; + std::size_t index = 0; + wp.reserve(lp.size()); + // Attempt read the weight in a double format, return false if it fails + while ((weights_ifstr >> weight) && (index < lp.size())) { + wp.push_back(Weighted_point_3(lp[index], weight)); + index++; + } + if (index != lp.size()) { + std::cerr << "Bad number of weights in file " << argv[2] << std::endl; + usage(argv[0]); + } + } else { + std::cerr << "Unable to read file " << argv[2] << std::endl; + usage(argv[0]); + } + + // Read iso_cuboid_3 information from file + std::ifstream iso_cuboid_str(argv[3]); + double x_min, y_min, z_min, x_max, y_max, z_max; + if (iso_cuboid_str.good()) { + iso_cuboid_str >> x_min >> y_min >> z_min >> x_max >> y_max >> z_max; + } else { + std::cerr << "Unable to read file " << argv[3] << std::endl; + usage(argv[0]); + } + + // Define the periodic cube + P3RT3 prt(PK::Iso_cuboid_3(x_min, y_min, z_min, x_max, y_max, z_max)); + // Heuristic for inserting large point sets (if pts is reasonably large) + prt.insert(wp.begin(), wp.end(), true); + // As prt won't be modified anymore switch to 1-sheeted cover if possible + if (prt.is_triangulation_in_1_sheet()) prt.convert_to_1_sheeted_covering(); + std::cout << "Periodic Delaunay computed." << std::endl; + + // alpha shape construction from points. CGAL has a strange behavior in REGULARIZED mode. This is the default mode + // Maybe need to set it to GENERAL mode + Alpha_shape_3 as(prt, 0, Alpha_shape_3::GENERAL); + + // 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)); + + 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 + + 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; + ST 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(); + int dim_max = 0; + Filtration_value filtration_max = 0.0; + 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<Vertex_list, Cell_handle>(*cell); + count_cells++; + if (dim_max < 3) { + // Cell is of dim 3 + dim_max = 3; + } + } else if (const Facet* facet = CGAL::object_cast<Facet>(&object_iterator)) { + vertex_list = from_facet<Vertex_list, Facet>(*facet); + count_facets++; + if (dim_max < 2) { + // Facet is of dim 2 + dim_max = 2; + } + } else if (const Edge_3* edge = CGAL::object_cast<Edge_3>(&object_iterator)) { + vertex_list = from_edge<Vertex_list, Edge_3>(*edge); + count_edges++; + if (dim_max < 1) { + // Edge_3 is of dim 1 + dim_max = 1; + } + } else if (const Vertex_handle* vertex = CGAL::object_cast<Vertex_handle>(&object_iterator)) { + count_vertices++; + vertex_list = from_vertex<Vertex_list, Vertex_handle>(*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 " << 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; +#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 + Filtration_value filtr = /*std::sqrt*/ (*the_alpha_value_iterator); +#ifdef DEBUG_TRACES + std::cout << "filtration = " << filtr << std::endl; +#endif // DEBUG_TRACES + if (filtr > filtration_max) { + filtration_max = filtr; + } + simplex_tree.insert_simplex(the_simplex_tree, filtr); + if (the_alpha_value_iterator != the_alpha_values.end()) + ++the_alpha_value_iterator; + else + std::cout << "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 << "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; + std::cout << " Dimension = " << simplex_tree.dimension() << " "; +#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 + + // Sort the simplices in the order of the filtration + simplex_tree.initialize_filtration(); + + std::cout << "Simplex_tree dim: " << simplex_tree.dimension() << std::endl; + // Compute the persistence diagram of the complex + Persistent_cohomology pcoh(simplex_tree, true); + // initializes the coefficient field for homology + pcoh.init_coefficients(coeff_field_characteristic); + + pcoh.compute_persistent_cohomology(min_persistence); + + pcoh.output_diagram(); + + return 0; +} diff --git a/src/Persistent_cohomology/test/betti_numbers_unit_test.cpp b/src/Persistent_cohomology/test/betti_numbers_unit_test.cpp index da418034..0a08d200 100644 --- a/src/Persistent_cohomology/test/betti_numbers_unit_test.cpp +++ b/src/Persistent_cohomology/test/betti_numbers_unit_test.cpp @@ -62,8 +62,6 @@ BOOST_AUTO_TEST_CASE( plain_homology_betti_numbers ) st.insert_simplex_and_subfaces(edge04); st.insert_simplex(edge14); st.insert_simplex(vertex5); - // FIXME: Remove this line - st.set_dimension(3); // Sort the simplices in the order of the filtration st.initialize_filtration(); @@ -170,8 +168,6 @@ BOOST_AUTO_TEST_CASE( betti_numbers ) st.insert_simplex_and_subfaces(edge04, 2.0); st.insert_simplex(edge14, 2.0); st.insert_simplex(vertex5, 1.0); - // FIXME: Remove this line - st.set_dimension(3); // Sort the simplices in the order of the filtration st.initialize_filtration(); diff --git a/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp b/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp index f53987b6..a1c106d5 100644 --- a/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp +++ b/src/Persistent_cohomology/test/persistent_cohomology_unit_test.cpp @@ -196,8 +196,6 @@ BOOST_AUTO_TEST_CASE( persistence_constructor_exception ) // To make number of simplices = 255 const short simplex_0[] = {0, 1, 2, 3, 4, 5, 6, 7}; st.insert_simplex_and_subfaces(simplex_0); - // FIXME: Remove this line - st.set_dimension(8); // Sort the simplices in the order of the filtration st.initialize_filtration(); diff --git a/src/Simplex_tree/doc/Intro_simplex_tree.h b/src/Simplex_tree/doc/Intro_simplex_tree.h index f5b72ff6..769491d9 100644 --- a/src/Simplex_tree/doc/Intro_simplex_tree.h +++ b/src/Simplex_tree/doc/Intro_simplex_tree.h @@ -67,10 +67,13 @@ Information of the Simplex Tree: Number of vertices = 10 Number of simplices = 98 \endcode * * \li <a href="_simplex_tree_2example_alpha_shapes_3_simplex_tree_from_off_file_8cpp-example.html"> - * Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp</a> - Simplex tree is computed and displayed from a 3D alpha - * complex (Requires CGAL, GMP and GMPXX to be installed) - * + * Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp</a> - Simplex tree is computed and displayed + * from a 3D alpha complex (Requires CGAL, GMP and GMPXX to be installed). * + * \li <a href="_simplex_tree_2graph_expansion_with_blocker_8cpp-example.html"> + * Simplex_tree/graph_expansion_with_blocker.cpp</a> - Simple simplex tree construction from a one-skeleton graph with + * a simple blocker expansion method. + * * \subsection filteredcomplexeshassecomplex Hasse complex * The second one is the Hasse_complex. The Hasse complex is a data structure representing explicitly all co-dimension * 1 incidence relations in a complex. It is consequently faster when accessing the boundary of a simplex, but is less diff --git a/src/Simplex_tree/example/CMakeLists.txt b/src/Simplex_tree/example/CMakeLists.txt index e22cc92c..8bc4ad53 100644 --- a/src/Simplex_tree/example/CMakeLists.txt +++ b/src/Simplex_tree/example/CMakeLists.txt @@ -34,5 +34,12 @@ if(GMP_FOUND AND CGAL_FOUND) "${CMAKE_SOURCE_DIR}/data/points/bunny_5000.off") install(TARGETS Simplex_tree_example_alpha_shapes_3_from_off DESTINATION bin) +endif() +add_executable ( Simplex_tree_example_graph_expansion_with_blocker graph_expansion_with_blocker.cpp ) +if (TBB_FOUND) + target_link_libraries(Simplex_tree_example_graph_expansion_with_blocker ${TBB_LIBRARIES}) endif() +add_test(NAME Simplex_tree_example_graph_expansion_with_blocker COMMAND $<TARGET_FILE:Simplex_tree_example_graph_expansion_with_blocker>) + +install(TARGETS Simplex_tree_example_graph_expansion_with_blocker DESTINATION bin) diff --git a/src/Simplex_tree/example/graph_expansion_with_blocker.cpp b/src/Simplex_tree/example/graph_expansion_with_blocker.cpp new file mode 100644 index 00000000..86bfb8cb --- /dev/null +++ b/src/Simplex_tree/example/graph_expansion_with_blocker.cpp @@ -0,0 +1,79 @@ +/* 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 + * + * 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> + +using Simplex_tree = Gudhi::Simplex_tree<>; +using Simplex_handle = Simplex_tree::Simplex_handle; + +int main(int argc, char * const argv[]) { + + // Construct the Simplex Tree with a 1-skeleton graph example + Simplex_tree simplexTree; + + simplexTree.insert_simplex({0, 1}, 0.); + simplexTree.insert_simplex({0, 2}, 1.); + simplexTree.insert_simplex({0, 3}, 2.); + simplexTree.insert_simplex({1, 2}, 3.); + simplexTree.insert_simplex({1, 3}, 4.); + simplexTree.insert_simplex({2, 3}, 5.); + simplexTree.insert_simplex({2, 4}, 6.); + simplexTree.insert_simplex({3, 6}, 7.); + simplexTree.insert_simplex({4, 5}, 8.); + simplexTree.insert_simplex({4, 6}, 9.); + simplexTree.insert_simplex({5, 6}, 10.); + simplexTree.insert_simplex({6}, 10.); + + simplexTree.expansion_with_blockers(3, [&](Simplex_handle sh){ + bool result = false; + std::cout << "Blocker on ["; + // User can loop on the vertices from the given simplex_handle i.e. + for (auto vertex : simplexTree.simplex_vertex_range(sh)) { + // We block the expansion, if the vertex '6' is in the given list of vertices + if (vertex == 6) + result = true; + std::cout << vertex << ", "; + } + std::cout << "] ( " << simplexTree.filtration(sh); + // User can re-assign a new filtration value directly in the blocker (default is the maximal value of boudaries) + simplexTree.assign_filtration(sh, simplexTree.filtration(sh) + 1.); + + std::cout << " + 1. ) = " << result << std::endl; + + return result; + }); + + std::cout << "********************************************************************\n"; + std::cout << "* The complex contains " << simplexTree.num_simplices() << " simplices"; + std::cout << " - dimension " << simplexTree.dimension() << "\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 << "(" << vertex << ")"; + std::cout << std::endl; + } + + return 0; +} diff --git a/src/Simplex_tree/example/mini_simplex_tree.cpp b/src/Simplex_tree/example/mini_simplex_tree.cpp index ad99df23..19e45361 100644 --- a/src/Simplex_tree/example/mini_simplex_tree.cpp +++ b/src/Simplex_tree/example/mini_simplex_tree.cpp @@ -52,8 +52,6 @@ int main() { 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); diff --git a/src/Simplex_tree/example/simple_simplex_tree.cpp b/src/Simplex_tree/example/simple_simplex_tree.cpp index d8318f03..b6b65b88 100644 --- a/src/Simplex_tree/example/simple_simplex_tree.cpp +++ b/src/Simplex_tree/example/simple_simplex_tree.cpp @@ -185,7 +185,6 @@ int main(int argc, char * const argv[]) { } // ++ GENERAL VARIABLE SET - simplexTree.set_dimension(2); // Max dimension = 2 -> (2,1,0) std::cout << "********************************************************************\n"; // Display the Simplex_tree - Can not be done in the middle of 2 inserts @@ -194,9 +193,8 @@ int main(int argc, char * const argv[]) { 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 << static_cast<int>(vertex) << " "; - } + for (auto vertex : simplexTree.simplex_vertex_range(f_simplex)) + std::cout << "(" << vertex << ")"; std::cout << std::endl; } // [0.1] 0 @@ -249,5 +247,34 @@ int main(int argc, char * const argv[]) { std::cout << "***+ YES IT IS!\n"; else std::cout << "***- NO IT ISN'T\n"; + + simplexFound = simplexTree.find({ 0, 1 }); + std::cout << "**************IS THE SIMPLEX {0,1} IN THE SIMPLEX TREE ?\n"; + if (simplexFound != simplexTree.null_simplex()) + std::cout << "***+ YES IT IS!\n"; + else + std::cout << "***- NO IT ISN'T\n"; + + std::cout << "**************COFACES OF {0,1} IN CODIMENSION 1 ARE\n"; + for (auto& simplex : simplexTree.cofaces_simplex_range(simplexTree.find({0,1}), 1)) { + for (auto vertex : simplexTree.simplex_vertex_range(simplex)) + std::cout << "(" << vertex << ")"; + std::cout << std::endl; + } + + std::cout << "**************STARS OF {0,1} ARE\n"; + for (auto& simplex : simplexTree.star_simplex_range(simplexTree.find({0,1}))) { + for (auto vertex : simplexTree.simplex_vertex_range(simplex)) + std::cout << "(" << vertex << ")"; + std::cout << std::endl; + } + + std::cout << "**************BOUNDARIES OF {0,1,2} ARE\n"; + for (auto& simplex : simplexTree.boundary_simplex_range(simplexTree.find({0,1,2}))) { + for (auto vertex : simplexTree.simplex_vertex_range(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 37b3ea97..7da767cb 100644 --- a/src/Simplex_tree/include/gudhi/Simplex_tree.h +++ b/src/Simplex_tree/include/gudhi/Simplex_tree.h @@ -482,7 +482,17 @@ class Simplex_tree { } /** \brief Returns an upper bound on the dimension of the simplicial complex. */ - int dimension() const { + int upper_bound_dimension() const { + return dimension_; + } + + /** \brief Returns the dimension of the simplicial complex. + \details This function is not constant time because it can recompute dimension if required (can be triggered by + `remove_maximal_simplex()` or `prune_above_filtration()`). + */ + int dimension() { + if (dimension_to_be_lowered_) + lower_upper_bound_dimension(); return dimension_; } @@ -591,7 +601,11 @@ class Simplex_tree { // if filtration value unchanged return std::pair<Simplex_handle, bool>(null_simplex(), false); } - // otherwise the insertion has succeeded + // otherwise the insertion has succeeded - size is a size_type + if (static_cast<int>(simplex.size()) - 1 > dimension_) { + // Update dimension if needed + dimension_ = static_cast<int>(simplex.size()) - 1; + } return res_insert; } @@ -1067,6 +1081,118 @@ class Simplex_tree { } public: + /** \brief Expands a simplex tree containing only a graph. Simplices corresponding to cliques in the graph are added + * incrementally, faces before cofaces, unless the simplex has dimension larger than `max_dim` or `block_simplex` + * returns true for this simplex. + * + * @param[in] max_dim Expansion maximal dimension value. + * @param[in] block_simplex Blocker oracle. Its concept is <CODE>bool block_simplex(Simplex_handle sh)</CODE> + * + * The function identifies a candidate simplex whose faces are all already in the complex, inserts + * it with a filtration value corresponding to the maximum of the filtration values of the faces, then calls + * `block_simplex` on a `Simplex_handle` for this new simplex. If `block_simplex` returns true, the simplex is + * removed, otherwise it is kept. Note that the evaluation of `block_simplex` is a good time to update the + * filtration value of the simplex if you want a customized value. The algorithm then proceeds with the next + * candidate. + * + * @warning several candidates of the same dimension may be inserted simultaneously before calling `block_simplex`, + * so if you examine the complex in `block_simplex`, you may hit a few simplices of the same dimension that have not + * been vetted by `block_simplex` yet, or have already been rejected but not yet removed. + */ + template< typename Blocker > + void expansion_with_blockers(int max_dim, Blocker block_simplex) { + // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree + for (auto& simplex : boost::adaptors::reverse(root_.members())) { + if (has_children(&simplex)) { + siblings_expansion_with_blockers(simplex.second.children(), max_dim, max_dim - 1, block_simplex); + } + } + } + + private: + /** \brief Recursive expansion with blockers of the simplex tree.*/ + template< typename Blocker > + void siblings_expansion_with_blockers(Siblings* siblings, int max_dim, int k, Blocker block_simplex) { + if (dimension_ < max_dim - k) { + dimension_ = max_dim - k; + } + if (k == 0) + return; + // No need to go deeper + if (siblings->members().size() < 2) + return; + // Reverse loop starting before the last one for 'next' to be the last one + for (auto simplex = siblings->members().rbegin() + 1; simplex != siblings->members().rend(); simplex++) { + std::vector<std::pair<Vertex_handle, Node> > intersection; + for(auto next = siblings->members().rbegin(); next != simplex; next++) { + bool to_be_inserted = true; + Filtration_value filt = simplex->second.filtration(); + // If all the boundaries are present, 'next' needs to be inserted + for (Simplex_handle border : boundary_simplex_range(simplex)) { + Simplex_handle border_child = find_child(border, next->first); + if (border_child == null_simplex()) { + to_be_inserted=false; + break; + } + filt = std::max(filt, filtration(border_child)); + } + if (to_be_inserted) { + intersection.emplace_back(next->first, Node(nullptr, filt)); + } + } + if (intersection.size() != 0) { + // Reverse the order to insert + Siblings * new_sib = new Siblings(siblings, // oncles + simplex->first, // parent + boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t + std::vector<Simplex_handle> blocked_new_sib_list; + // As all intersections are inserted, we can call the blocker function on all new_sib members + for (auto new_sib_member = new_sib->members().begin(); + new_sib_member != new_sib->members().end(); + new_sib_member++) { + bool blocker_result = block_simplex(new_sib_member); + // new_sib member has been blocked by the blocker function + // add it to the list to be removed - do not perform it while looping on it + if (blocker_result) + blocked_new_sib_list.push_back(new_sib_member); + } + bool removed = false; + for (auto& blocked_new_sib_member : blocked_new_sib_list){ + removed = removed || remove_maximal_simplex(blocked_new_sib_member); + } + if (removed) { + // ensure the children property + simplex->second.assign_children(siblings); + } else { + // ensure recursive call + simplex->second.assign_children(new_sib); + siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex); + } + } else { + // ensure the children property + simplex->second.assign_children(siblings); + } + } + } + + /* \private Returns the Simplex_handle composed of the vertex list (from the Simplex_handle), plus the given + * Vertex_handle if the Vertex_handle is found in the Simplex_handle children list. + * Returns null_simplex() if it does not exist + */ + Simplex_handle find_child(Simplex_handle sh, Vertex_handle vh) const { + if (!has_children(sh)) + return null_simplex(); + + Simplex_handle child = sh->second.children()->find(vh); + // Specific case of boost::flat_map does not find, returns boost::flat_map::end() + // in simplex tree we want a null_simplex() + if (child == sh->second.children()->members().end()) + return null_simplex(); + + return child; + } + + public: /** \brief Write the hasse diagram of the simplicial complex in os. * * Each row in the file correspond to a simplex. A line is written: @@ -1142,6 +1268,9 @@ class Simplex_tree { * \post Some simplex tree functions require the filtration to be valid. `prune_above_filtration()` * function is not launching `initialize_filtration()` but returns the filtration modification information. If the * complex has changed , please call `initialize_filtration()` to recompute it. + * \post Note that the dimension of the simplicial complex may be lower after calling `prune_above_filtration()` + * than it was before. However, `upper_bound_dimension()` will return the old value, which remains a valid upper + * bound. If you care, you can call `dimension()` to recompute the exact dimension. */ bool prune_above_filtration(Filtration_value filtration) { return rec_prune_above_filtration(root(), filtration); @@ -1153,6 +1282,8 @@ class Simplex_tree { auto last = std::remove_if(list.begin(), list.end(), [=](Dit_value_t& simplex) { if (simplex.second.filtration() <= filt) return false; if (has_children(&simplex)) rec_delete(simplex.second.children()); + // dimension may need to be lowered + dimension_to_be_lowered_ = true; return true; }); @@ -1161,6 +1292,8 @@ class Simplex_tree { // Removing the whole siblings, parent becomes a leaf. sib->oncles()->members()[sib->parent()].assign_children(sib->oncles()); delete sib; + // dimension may need to be lowered + dimension_to_be_lowered_ = true; return true; } else { // Keeping some elements of siblings. Remove the others, and recurse in the remaining ones. @@ -1172,14 +1305,49 @@ class Simplex_tree { return modified; } + private: + /** \brief Deep search simplex tree dimension recompute. + * @return True if the dimension was modified, false otherwise. + * \pre Be sure the simplex tree has not a too low dimension value as the deep search stops when the former dimension + * has been reached (cf. `upper_bound_dimension()` and `set_dimension()` methods). + */ + bool lower_upper_bound_dimension() { + // reset automatic detection to recompute + dimension_to_be_lowered_ = false; + int new_dimension = -1; + // Browse the tree from the left to the right as higher dimension cells are more likely on the left part of the tree + for (Simplex_handle sh : complex_simplex_range()) { +#ifdef DEBUG_TRACES + for (auto vertex : simplex_vertex_range(sh)) { + std::cout << " " << vertex; + } + std::cout << std::endl; +#endif // DEBUG_TRACES + + int sh_dimension = dimension(sh); + if (sh_dimension >= dimension_) + // Stop browsing as soon as the dimension is reached, no need to go furter + return false; + new_dimension = std::max(new_dimension, sh_dimension); + } + dimension_ = new_dimension; + return true; + } + + public: /** \brief Remove a maximal simplex. * @param[in] sh Simplex handle on the maximal simplex to remove. + * @return a boolean value that is an implementation detail, and that the user is supposed to ignore * \pre Please check the simplex has no coface before removing it. * \exception std::invalid_argument In debug mode, if sh has children. - * \post Be aware that removing is shifting data in a flat_map (initialize_filtration to be done). + * \post Be aware that removing is shifting data in a flat_map (`initialize_filtration()` to be done). + * \post Note that the dimension of the simplicial complex may be lower after calling `remove_maximal_simplex()` + * than it was before. However, `upper_bound_dimension()` will return the old value, which remains a valid upper + * bound. If you care, you can call `dimension()` to recompute the exact dimension. + * \internal @return true if the leaf's branch has no other leaves (branch's children has been re-assigned), false otherwise. */ - void remove_maximal_simplex(Simplex_handle sh) { + bool remove_maximal_simplex(Simplex_handle sh) { // Guarantee the simplex has no children GUDHI_CHECK(!has_children(sh), std::invalid_argument("Simplex_tree::remove_maximal_simplex - argument has children")); @@ -1195,7 +1363,11 @@ class Simplex_tree { // Sibling is emptied : must be deleted, and its parent must point on his own Sibling child->oncles()->members().at(child->parent()).assign_children(child->oncles()); delete child; + // dimension may need to be lowered + dimension_to_be_lowered_ = true; + return true; } + return false; } private: @@ -1207,6 +1379,7 @@ class Simplex_tree { std::vector<Simplex_handle> filtration_vect_; /** \brief Upper bound on the dimension of the simplicial complex.*/ int dimension_; + bool dimension_to_be_lowered_ = false; }; // Print a Simplex_tree in os. diff --git a/src/Simplex_tree/test/CMakeLists.txt b/src/Simplex_tree/test/CMakeLists.txt index 81999de6..8684ad2a 100644 --- a/src/Simplex_tree/test/CMakeLists.txt +++ b/src/Simplex_tree/test/CMakeLists.txt @@ -3,13 +3,29 @@ project(Simplex_tree_tests) include(GUDHI_test_coverage) +# Do not forget to copy test files in current binary dir +file(COPY "simplex_tree_for_unit_test.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + add_executable ( Simplex_tree_test_unit simplex_tree_unit_test.cpp ) target_link_libraries(Simplex_tree_test_unit ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) if (TBB_FOUND) target_link_libraries(Simplex_tree_test_unit ${TBB_LIBRARIES}) endif() -# Do not forget to copy test files in current binary dir -file(COPY "simplex_tree_for_unit_test.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) - gudhi_add_coverage_test(Simplex_tree_test_unit) + +add_executable ( Simplex_tree_remove_test_unit simplex_tree_remove_unit_test.cpp ) +target_link_libraries(Simplex_tree_remove_test_unit ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +if (TBB_FOUND) + target_link_libraries(Simplex_tree_remove_test_unit ${TBB_LIBRARIES}) +endif() + +gudhi_add_coverage_test(Simplex_tree_remove_test_unit) + +add_executable ( Simplex_tree_iostream_operator_test_unit simplex_tree_iostream_operator_unit_test.cpp ) +target_link_libraries(Simplex_tree_iostream_operator_test_unit ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +if (TBB_FOUND) + target_link_libraries(Simplex_tree_iostream_operator_test_unit ${TBB_LIBRARIES}) +endif() + +gudhi_add_coverage_test(Simplex_tree_iostream_operator_test_unit) diff --git a/src/Simplex_tree/test/README b/src/Simplex_tree/test/README index 21c3d871..df2ab89a 100644 --- a/src/Simplex_tree/test/README +++ b/src/Simplex_tree/test/README @@ -9,6 +9,6 @@ make To launch with details: *********************** -./SimplexTreeUT --report_level=detailed --log_level=all +./Simplex_tree_test_unit --report_level=detailed --log_level=all ==> echo $? returns 0 in case of success (non-zero otherwise) diff --git a/src/Simplex_tree/test/simplex_tree_graph_expansion_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_graph_expansion_unit_test.cpp new file mode 100644 index 00000000..19ce3321 --- /dev/null +++ b/src/Simplex_tree/test/simplex_tree_graph_expansion_unit_test.cpp @@ -0,0 +1,235 @@ +#include <iostream> +#include <fstream> +#include <string> +#include <algorithm> +#include <utility> // std::pair, std::make_pair +#include <cmath> // float comparison +#include <limits> +#include <functional> // greater + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "simplex_tree" +#include <boost/test/unit_test.hpp> +#include <boost/mpl/list.hpp> + +// ^ +// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined. +#include "gudhi/Simplex_tree.h" + +using namespace Gudhi; + +typedef boost::mpl::list<Simplex_tree<>, Simplex_tree<Simplex_tree_options_fast_persistence>> list_of_tested_variants; + + +bool AreAlmostTheSame(float a, float b) { + return std::fabs(a - b) < std::numeric_limits<float>::epsilon(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_3, typeST, list_of_tested_variants) { + using Simplex_handle = typename typeST::Simplex_handle; + // Construct the Simplex Tree with a 1-skeleton graph example + typeST simplex_tree; + + simplex_tree.insert_simplex({0, 1}, 0.); + simplex_tree.insert_simplex({0, 2}, 1.); + simplex_tree.insert_simplex({0, 3}, 2.); + simplex_tree.insert_simplex({1, 2}, 3.); + simplex_tree.insert_simplex({1, 3}, 4.); + simplex_tree.insert_simplex({2, 3}, 5.); + simplex_tree.insert_simplex({2, 4}, 6.); + simplex_tree.insert_simplex({3, 6}, 7.); + simplex_tree.insert_simplex({4, 5}, 8.); + simplex_tree.insert_simplex({4, 6}, 9.); + simplex_tree.insert_simplex({5, 6}, 10.); + simplex_tree.insert_simplex({6}, 10.); + + simplex_tree.expansion_with_blockers(3, [&](Simplex_handle sh){ + bool result = false; + std::cout << "Blocker on ["; + // User can loop on the vertices from the given simplex_handle i.e. + for (auto vertex : simplex_tree.simplex_vertex_range(sh)) { + // We block the expansion, if the vertex '6' is in the given list of vertices + if (vertex == 6) + result = true; + std::cout << vertex << ", "; + } + std::cout << "] ( " << simplex_tree.filtration(sh); + // User can re-assign a new filtration value directly in the blocker (default is the maximal value of boudaries) + simplex_tree.assign_filtration(sh, simplex_tree.filtration(sh) + 1.); + + std::cout << " + 1. ) = " << result << std::endl; + + return result; + }); + + std::cout << "********************************************************************\n"; + std::cout << "simplex_tree_expansion_with_blockers_3\n"; + std::cout << "********************************************************************\n"; + std::cout << "* The complex contains " << simplex_tree.num_simplices() << " simplices"; + std::cout << " - dimension " << simplex_tree.dimension() << "\n"; + std::cout << "* 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; + } + + BOOST_CHECK(simplex_tree.num_simplices() == 23); + BOOST_CHECK(simplex_tree.dimension() == 3); + // {4, 5, 6} shall be blocked + BOOST_CHECK(simplex_tree.find({4, 5, 6}) == simplex_tree.null_simplex()); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 4.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 5.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 6.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 6.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2,3})), 7.)); + +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_with_blockers_2, typeST, list_of_tested_variants) { + using Simplex_handle = typename typeST::Simplex_handle; + // Construct the Simplex Tree with a 1-skeleton graph example + typeST simplex_tree; + + simplex_tree.insert_simplex({0, 1}, 0.); + simplex_tree.insert_simplex({0, 2}, 1.); + simplex_tree.insert_simplex({0, 3}, 2.); + simplex_tree.insert_simplex({1, 2}, 3.); + simplex_tree.insert_simplex({1, 3}, 4.); + simplex_tree.insert_simplex({2, 3}, 5.); + simplex_tree.insert_simplex({2, 4}, 6.); + simplex_tree.insert_simplex({3, 6}, 7.); + simplex_tree.insert_simplex({4, 5}, 8.); + simplex_tree.insert_simplex({4, 6}, 9.); + simplex_tree.insert_simplex({5, 6}, 10.); + simplex_tree.insert_simplex({6}, 10.); + + simplex_tree.expansion_with_blockers(2, [&](Simplex_handle sh){ + bool result = false; + std::cout << "Blocker on ["; + // User can loop on the vertices from the given simplex_handle i.e. + for (auto vertex : simplex_tree.simplex_vertex_range(sh)) { + // We block the expansion, if the vertex '6' is in the given list of vertices + if (vertex == 6) + result = true; + std::cout << vertex << ", "; + } + std::cout << "] ( " << simplex_tree.filtration(sh); + // User can re-assign a new filtration value directly in the blocker (default is the maximal value of boudaries) + simplex_tree.assign_filtration(sh, simplex_tree.filtration(sh) + 1.); + + std::cout << " + 1. ) = " << result << std::endl; + + return result; + }); + + std::cout << "********************************************************************\n"; + std::cout << "simplex_tree_expansion_with_blockers_2\n"; + std::cout << "********************************************************************\n"; + std::cout << "* The complex contains " << simplex_tree.num_simplices() << " simplices"; + std::cout << " - dimension " << simplex_tree.dimension() << "\n"; + std::cout << "* 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; + } + + BOOST_CHECK(simplex_tree.num_simplices() == 22); + BOOST_CHECK(simplex_tree.dimension() == 2); + // {4, 5, 6} shall be blocked + BOOST_CHECK(simplex_tree.find({4, 5, 6}) == simplex_tree.null_simplex()); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 4.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 5.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 6.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 6.)); + BOOST_CHECK(simplex_tree.find({0,1,2,3}) == simplex_tree.null_simplex()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion, typeST, list_of_tested_variants) { + // Construct the Simplex Tree with a 1-skeleton graph example + typeST simplex_tree; + + simplex_tree.insert_simplex({0, 1}, 0.); + simplex_tree.insert_simplex({0, 2}, 1.); + simplex_tree.insert_simplex({0, 3}, 2.); + simplex_tree.insert_simplex({1, 2}, 3.); + simplex_tree.insert_simplex({1, 3}, 4.); + simplex_tree.insert_simplex({2, 3}, 5.); + simplex_tree.insert_simplex({2, 4}, 6.); + simplex_tree.insert_simplex({3, 6}, 7.); + simplex_tree.insert_simplex({4, 5}, 8.); + simplex_tree.insert_simplex({4, 6}, 9.); + simplex_tree.insert_simplex({5, 6}, 10.); + simplex_tree.insert_simplex({6}, 10.); + + simplex_tree.expansion(3); + std::cout << "********************************************************************\n"; + std::cout << "simplex_tree_expansion_3\n"; + std::cout << "********************************************************************\n"; + std::cout << "* The complex contains " << simplex_tree.num_simplices() << " simplices"; + std::cout << " - dimension " << simplex_tree.dimension() << "\n"; + std::cout << "* 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; + } + + BOOST_CHECK(simplex_tree.num_simplices() == 24); + BOOST_CHECK(simplex_tree.dimension() == 3); + + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({4,5,6})), 10.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 3.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 4.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 5.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 5.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2,3})), 5.)); + +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_expansion_2, typeST, list_of_tested_variants) { + // Construct the Simplex Tree with a 1-skeleton graph example + typeST simplex_tree; + + simplex_tree.insert_simplex({0, 1}, 0.); + simplex_tree.insert_simplex({0, 2}, 1.); + simplex_tree.insert_simplex({0, 3}, 2.); + simplex_tree.insert_simplex({1, 2}, 3.); + simplex_tree.insert_simplex({1, 3}, 4.); + simplex_tree.insert_simplex({2, 3}, 5.); + simplex_tree.insert_simplex({2, 4}, 6.); + simplex_tree.insert_simplex({3, 6}, 7.); + simplex_tree.insert_simplex({4, 5}, 8.); + simplex_tree.insert_simplex({4, 6}, 9.); + simplex_tree.insert_simplex({5, 6}, 10.); + simplex_tree.insert_simplex({6}, 10.); + + simplex_tree.expansion(2); + + std::cout << "********************************************************************\n"; + std::cout << "simplex_tree_expansion_2\n"; + std::cout << "********************************************************************\n"; + std::cout << "* The complex contains " << simplex_tree.num_simplices() << " simplices"; + std::cout << " - dimension " << simplex_tree.dimension() << "\n"; + std::cout << "* 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; + } + + BOOST_CHECK(simplex_tree.num_simplices() == 23); + BOOST_CHECK(simplex_tree.dimension() == 2); + + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({4,5,6})), 10.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,2})), 3.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,1,3})), 4.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({0,2,3})), 5.)); + BOOST_CHECK(AreAlmostTheSame(simplex_tree.filtration(simplex_tree.find({1,2,3})), 5.)); + BOOST_CHECK(simplex_tree.find({0,1,2,3}) == simplex_tree.null_simplex()); +} diff --git a/src/Simplex_tree/test/simplex_tree_iostream_operator_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_iostream_operator_unit_test.cpp new file mode 100644 index 00000000..ecb9f025 --- /dev/null +++ b/src/Simplex_tree/test/simplex_tree_iostream_operator_unit_test.cpp @@ -0,0 +1,136 @@ +#include <iostream> + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "simplex_tree_iostream_operator" +#include <boost/test/unit_test.hpp> +#include <boost/mpl/list.hpp> + +// ^ +// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined. +#include "gudhi/Simplex_tree.h" + +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 boost::mpl::list<Simplex_tree<>, + Simplex_tree<Simplex_tree_options_fast_persistence> + > list_of_tested_variants; + +BOOST_AUTO_TEST_CASE_TEMPLATE(iostream_operator, Stree_type, list_of_tested_variants) { + std::cout << "********************************************************************" << std::endl; + std::cout << "SIMPLEX TREE IOSTREAM OPERATOR" << std::endl; + + Stree_type st; + + st.insert_simplex_and_subfaces({0, 1, 6, 7}, 4.0); + st.insert_simplex_and_subfaces({3, 4, 5}, 3.0); + st.insert_simplex_and_subfaces({3, 0}, 2.0); + st.insert_simplex_and_subfaces({2, 1, 0}, 3.0); + + st.initialize_filtration(); + // Display the Simplex_tree + std::cout << "The ORIGINAL complex contains " << st.num_simplices() << " simplices - dimension = " + << st.dimension() << 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()) { + std::cout << " " << "[" << st.filtration(f_simplex) << "] "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; + } + std::cout << std::endl; + } + + // st: + // 1 6 + // o---o + // /X\7/ + // o---o---o---o + // 2 0 3\X/4 + // o + // 5 + std::string iostream_file("simplex_tree_for_iostream_operator_unit_test.txt"); + std::ofstream simplex_tree_ostream(iostream_file.c_str()); + simplex_tree_ostream << st; + simplex_tree_ostream.close(); + + Stree_type read_st; + std::ifstream simplex_tree_istream(iostream_file.c_str()); + simplex_tree_istream >> read_st; + + // Display the Simplex_tree + std::cout << "The READ complex contains " << read_st.num_simplices() << " simplices - dimension = " + << read_st.dimension() << std::endl; + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + for (auto f_simplex : read_st.filtration_simplex_range()) { + std::cout << " " << "[" << read_st.filtration(f_simplex) << "] "; + for (auto vertex : read_st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; + } + std::cout << std::endl; + } + + BOOST_CHECK(st == read_st); +} + + +BOOST_AUTO_TEST_CASE(mini_iostream_operator) { + std::cout << "********************************************************************" << std::endl; + std::cout << "MINI SIMPLEX TREE IOSTREAM OPERATOR" << std::endl; + + Simplex_tree<MyOptions> st; + + st.insert_simplex_and_subfaces({0, 1, 6, 7}); + st.insert_simplex_and_subfaces({3, 4, 5}); + st.insert_simplex_and_subfaces({3, 0}); + st.insert_simplex_and_subfaces({2, 1, 0}); + + st.initialize_filtration(); + // Display the Simplex_tree + std::cout << "The ORIGINAL complex contains " << st.num_simplices() << " simplices - dimension = " + << st.dimension() << 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 << (int) vertex << " "; + } + std::cout << std::endl; + } + + // st: + // 1 6 + // o---o + // /X\7/ + // o---o---o---o + // 2 0 3\X/4 + // o + // 5 + std::string iostream_file("simplex_tree_for_iostream_operator_unit_test.txt"); + std::ofstream simplex_tree_ostream(iostream_file.c_str()); + simplex_tree_ostream << st; + simplex_tree_ostream.close(); + + Simplex_tree<MyOptions> read_st; + std::ifstream simplex_tree_istream(iostream_file.c_str()); + simplex_tree_istream >> read_st; + + // Display the Simplex_tree + std::cout << "The READ complex contains " << read_st.num_simplices() << " simplices - dimension = " + << read_st.dimension() << std::endl; + std::cout << std::endl << std::endl << "Iterator on Simplices in the filtration, with [filtration value]:" << std::endl; + for (auto f_simplex : read_st.filtration_simplex_range()) { + std::cout << " " << "[" << read_st.filtration(f_simplex) << "] "; + for (auto vertex : read_st.simplex_vertex_range(f_simplex)) { + std::cout << (int) vertex << " "; + } + std::cout << std::endl; + } + + BOOST_CHECK(st == read_st); +} diff --git a/src/Simplex_tree/test/simplex_tree_remove_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_remove_unit_test.cpp new file mode 100644 index 00000000..dc37375c --- /dev/null +++ b/src/Simplex_tree/test/simplex_tree_remove_unit_test.cpp @@ -0,0 +1,427 @@ +#include <iostream> + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "simplex_tree_remove" +#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; + +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; +}; + +using Mini_stree = Simplex_tree<MyOptions>; +using Stree = Simplex_tree<>; + +BOOST_AUTO_TEST_CASE(remove_maximal_simplex) { + std::cout << "********************************************************************" << std::endl; + std::cout << "REMOVE MAXIMAL SIMPLEX" << std::endl; + + Mini_stree st; + + st.insert_simplex_and_subfaces({0, 1, 6, 7}); + st.insert_simplex_and_subfaces({3, 4, 5}); + + // Constructs a copy at this state for further test purpose + Mini_stree st_pruned = st; + + st.insert_simplex_and_subfaces({3, 0}); + st.insert_simplex_and_subfaces({2, 1, 0}); + + // Constructs a copy at this state for further test purpose + Mini_stree st_complete = st; + // st_complete and st: + // 1 6 + // o---o + // /X\7/ + // o---o---o---o + // 2 0 3\X/4 + // o + // 5 + // st_pruned: + // 1 6 + // o---o + // \7/ + // o o---o + // 0 3\X/4 + // o + // 5 + +#ifdef GUDHI_DEBUG + std::cout << "Check exception throw in debug mode" << std::endl; + // throw excpt because sh has children + BOOST_CHECK_THROW (st.remove_maximal_simplex(st.find({0, 1, 6})), std::invalid_argument); + BOOST_CHECK_THROW (st.remove_maximal_simplex(st.find({3})), std::invalid_argument); + BOOST_CHECK(st == st_complete); +#endif + std::cout << "st.remove_maximal_simplex({0, 2})" << std::endl; + st.remove_maximal_simplex(st.find({0, 2})); + std::cout << "st.remove_maximal_simplex({0, 1, 2})" << std::endl; + st.remove_maximal_simplex(st.find({0, 1, 2})); + std::cout << "st.remove_maximal_simplex({1, 2})" << std::endl; + st.remove_maximal_simplex(st.find({1, 2})); + std::cout << "st.remove_maximal_simplex({2})" << std::endl; + st.remove_maximal_simplex(st.find({2})); + std::cout << "st.remove_maximal_simplex({3})" << std::endl; + st.remove_maximal_simplex(st.find({0, 3})); + + BOOST_CHECK(st == st_pruned); + // Remove all, but as the simplex tree is not storing filtration, there is no modification + st.prune_above_filtration(0.0); + BOOST_CHECK(st == st_pruned); + + Mini_stree st_wo_seven; + + st_wo_seven.insert_simplex_and_subfaces({0, 1, 6}); + st_wo_seven.insert_simplex_and_subfaces({3, 4, 5}); + // st_wo_seven: + // 1 6 + // o---o + // \X/ + // o o---o + // 0 3\X/4 + // o + // 5 + + // Remove all 7 to test the both remove_maximal_simplex cases (when _members is empty or not) + std::cout << "st.remove_maximal_simplex({0, 1, 6, 7})" << std::endl; + st.remove_maximal_simplex(st.find({0, 1, 6, 7})); + std::cout << "st.remove_maximal_simplex({0, 1, 7})" << std::endl; + st.remove_maximal_simplex(st.find({0, 1, 7})); + std::cout << "st.remove_maximal_simplex({0, 6, 7})" << std::endl; + st.remove_maximal_simplex(st.find({0, 6, 7})); + std::cout << "st.remove_maximal_simplex({0, 7})" << std::endl; + st.remove_maximal_simplex(st.find({0, 7})); + std::cout << "st.remove_maximal_simplex({1, 6, 7})" << std::endl; + st.remove_maximal_simplex(st.find({1, 6, 7})); + std::cout << "st.remove_maximal_simplex({1, 7})" << std::endl; + st.remove_maximal_simplex(st.find({1, 7})); + std::cout << "st.remove_maximal_simplex({6, 7})" << std::endl; + st.remove_maximal_simplex(st.find({6, 7})); + std::cout << "st.remove_maximal_simplex({7})" << std::endl; + st.remove_maximal_simplex(st.find({7})); + + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + + // Check dimension calls lower_upper_bound_dimension to recompute dimension + BOOST_CHECK(st.dimension() == 2); + BOOST_CHECK(st.upper_bound_dimension() == 2); + + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() + << " | st_wo_seven.upper_bound_dimension()=" << st_wo_seven.upper_bound_dimension() << std::endl; + std::cout << "st.dimension()=" << st.dimension() << " | st_wo_seven.dimension()=" << st_wo_seven.dimension() << std::endl; + BOOST_CHECK(st == st_wo_seven); +} + +BOOST_AUTO_TEST_CASE(auto_dimension_set) { + std::cout << "********************************************************************" << std::endl; + std::cout << "DIMENSION ON REMOVE MAXIMAL SIMPLEX" << std::endl; + + Mini_stree st; + + st.insert_simplex_and_subfaces({0, 1, 2}); + st.insert_simplex_and_subfaces({0, 1, 3}); + st.insert_simplex_and_subfaces({1, 2, 3, 4}); + st.insert_simplex_and_subfaces({1, 2, 3, 5}); + st.insert_simplex_and_subfaces({6, 7, 8, 9}); + st.insert_simplex_and_subfaces({6, 7, 8, 10}); + + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.remove_maximal_simplex({6, 7, 8, 10})" << std::endl; + st.remove_maximal_simplex(st.find({6, 7, 8, 10})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.remove_maximal_simplex({6, 7, 8, 9})" << std::endl; + st.remove_maximal_simplex(st.find({6, 7, 8, 9})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.remove_maximal_simplex({1, 2, 3, 4})" << std::endl; + st.remove_maximal_simplex(st.find({1, 2, 3, 4})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.remove_maximal_simplex({1, 2, 3, 5})" << std::endl; + st.remove_maximal_simplex(st.find({1, 2, 3, 5})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 2); + std::cout << "st.dimension()=" << st.dimension() << std::endl; + + std::cout << "st.insert_simplex_and_subfaces({1, 2, 3, 5})" << std::endl; + st.insert_simplex_and_subfaces({1, 2, 3, 5}); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.insert_simplex_and_subfaces({1, 2, 3, 4})" << std::endl; + st.insert_simplex_and_subfaces({1, 2, 3, 4}); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + + std::cout << "st.remove_maximal_simplex({1, 2, 3, 5})" << std::endl; + st.remove_maximal_simplex(st.find({1, 2, 3, 5})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + + std::cout << "st.remove_maximal_simplex({1, 2, 3, 4})" << std::endl; + st.remove_maximal_simplex(st.find({1, 2, 3, 4})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 2); + std::cout << "st.dimension()=" << st.dimension() << std::endl; + + std::cout << "st.insert_simplex_and_subfaces({0, 1, 3, 4})" << std::endl; + st.insert_simplex_and_subfaces({0, 1, 3, 4}); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.remove_maximal_simplex({0, 1, 3, 4})" << std::endl; + st.remove_maximal_simplex(st.find({0, 1, 3, 4})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 2); + std::cout << "st.dimension()=" << st.dimension() << std::endl; + + std::cout << "st.insert_simplex_and_subfaces({1, 2, 3, 5})" << std::endl; + st.insert_simplex_and_subfaces({1, 2, 3, 5}); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.insert_simplex_and_subfaces({1, 2, 3, 4})" << std::endl; + st.insert_simplex_and_subfaces({1, 2, 3, 4}); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + + // Check you can override the dimension + // This is a limit test case - shall not happen + st.set_dimension(1); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 1); + // check dimension() and lower_upper_bound_dimension() is not giving the right answer because dimension is too low + BOOST_CHECK(st.dimension() == 1); + + + // Check you can override the dimension + // This is a limit test case - shall not happen + st.set_dimension(6); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 6); + // check dimension() do not launch lower_upper_bound_dimension() + BOOST_CHECK(st.dimension() == 6); + + + // Reset with the correct value + st.set_dimension(3); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + BOOST_CHECK(st.dimension() == 3); + + std::cout << "st.insert_simplex_and_subfaces({0, 1, 2, 3, 4, 5, 6})" << std::endl; + st.insert_simplex_and_subfaces({0, 1, 2, 3, 4, 5, 6}); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 6); + BOOST_CHECK(st.dimension() == 6); + + std::cout << "st.remove_maximal_simplex({0, 1, 2, 3, 4, 5, 6})" << std::endl; + st.remove_maximal_simplex(st.find({0, 1, 2, 3, 4, 5, 6})); + std::cout << "st.upper_bound_dimension()=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 6); + BOOST_CHECK(st.dimension() == 5); + +} + +BOOST_AUTO_TEST_CASE(prune_above_filtration) { + std::cout << "********************************************************************" << std::endl; + std::cout << "PRUNE ABOVE FILTRATION" << std::endl; + + Stree st; + + st.insert_simplex_and_subfaces({0, 1, 6, 7}, 1.0); + st.insert_simplex_and_subfaces({3, 4, 5}, 2.0); + + // Constructs a copy at this state for further test purpose + Stree st_pruned = st; + st_pruned.initialize_filtration(); // reset + + st.insert_simplex_and_subfaces({3, 0}, 3.0); + st.insert_simplex_and_subfaces({2, 1, 0}, 4.0); + + // Constructs a copy at this state for further test purpose + Stree st_complete = st; + // st_complete and st: + // 1 6 + // o---o + // /X\7/ + // o---o---o---o + // 2 0 3\X/4 + // o + // 5 + // st_pruned: + // 1 6 + // o---o + // \7/ + // o o---o + // 0 3\X/4 + // o + // 5 + + bool simplex_is_changed = false; + // Check the no action cases + // greater than initial filtration value + simplex_is_changed = st.prune_above_filtration(10.0); + if (simplex_is_changed) + st.initialize_filtration(); + BOOST_CHECK(st == st_complete); + BOOST_CHECK(!simplex_is_changed); + // equal to initial filtration value + simplex_is_changed = st.prune_above_filtration(6.0); + if (simplex_is_changed) + st.initialize_filtration(); + BOOST_CHECK(st == st_complete); + BOOST_CHECK(!simplex_is_changed); + // lower than initial filtration value, but still greater than the maximum filtration value + simplex_is_changed = st.prune_above_filtration(5.0); + if (simplex_is_changed) + st.initialize_filtration(); + BOOST_CHECK(st == st_complete); + BOOST_CHECK(!simplex_is_changed); + + // Display the Simplex_tree + std::cout << "The complex contains " << st.num_simplices() << " simplices"; + std::cout << " - dimension " << st.dimension() << 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 << (int) vertex << " "; + } + std::cout << std::endl; + } + + // Check the pruned cases + simplex_is_changed = st.prune_above_filtration(2.5); + if (simplex_is_changed) + st.initialize_filtration(); + BOOST_CHECK(st == st_pruned); + BOOST_CHECK(simplex_is_changed); + + // Display the Simplex_tree + std::cout << "The complex pruned at 2.5 contains " << st.num_simplices() << " simplices"; + std::cout << " - dimension " << st.dimension() << std::endl; + + simplex_is_changed = st.prune_above_filtration(2.0); + if (simplex_is_changed) + st.initialize_filtration(); + + std::cout << "The complex pruned at 2.0 contains " << st.num_simplices() << " simplices"; + std::cout << " - dimension " << st.dimension() << std::endl; + + BOOST_CHECK(st == st_pruned); + BOOST_CHECK(!simplex_is_changed); + + Stree st_empty; + simplex_is_changed = st.prune_above_filtration(0.0); + BOOST_CHECK(simplex_is_changed == true); + if (simplex_is_changed) + st.initialize_filtration(); + + // Display the Simplex_tree + std::cout << "The complex pruned at 0.0 contains " << st.num_simplices() << " simplices"; + std::cout << " - upper_bound_dimension " << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == 3); + + BOOST_CHECK(st.dimension() == -1); + std::cout << "upper_bound_dimension=" << st.upper_bound_dimension() << std::endl; + BOOST_CHECK(st.upper_bound_dimension() == -1); + + BOOST_CHECK(st == st_empty); + BOOST_CHECK(simplex_is_changed); + + // Test case to the limit + simplex_is_changed = st.prune_above_filtration(-1.0); + if (simplex_is_changed) + st.initialize_filtration(); + BOOST_CHECK(st == st_empty); + BOOST_CHECK(!simplex_is_changed); +} + +BOOST_AUTO_TEST_CASE(mini_prune_above_filtration) { + std::cout << "********************************************************************" << std::endl; + std::cout << "MINI PRUNE ABOVE FILTRATION" << std::endl; + + Mini_stree st; + + st.insert_simplex_and_subfaces({0, 1, 6, 7}); + st.insert_simplex_and_subfaces({3, 4, 5}); + st.insert_simplex_and_subfaces({3, 0}); + st.insert_simplex_and_subfaces({2, 1, 0}); + + // st: + // 1 6 + // o---o + // /X\7/ + // o---o---o---o + // 2 0 3\X/4 + // o + // 5 + + st.initialize_filtration(); + + // Display the Simplex_tree + std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; + BOOST_CHECK(st.num_simplices() == 27); + + // Test case to the limit - With these options, there is no filtration, which means filtration is 0 + bool simplex_is_changed = st.prune_above_filtration(1.0); + if (simplex_is_changed) + st.initialize_filtration(); + // Display the Simplex_tree + std::cout << "The complex pruned at 1.0 contains " << st.num_simplices() << " simplices" << std::endl; + BOOST_CHECK(!simplex_is_changed); + BOOST_CHECK(st.num_simplices() == 27); + + simplex_is_changed = st.prune_above_filtration(0.0); + if (simplex_is_changed) + st.initialize_filtration(); + // Display the Simplex_tree + std::cout << "The complex pruned at 0.0 contains " << st.num_simplices() << " simplices" << std::endl; + BOOST_CHECK(!simplex_is_changed); + BOOST_CHECK(st.num_simplices() == 27); + + // Test case to the limit + simplex_is_changed = st.prune_above_filtration(-1.0); + if (simplex_is_changed) + st.initialize_filtration(); + // Display the Simplex_tree + std::cout << "The complex pruned at -1.0 contains " << st.num_simplices() << " simplices" << std::endl; + BOOST_CHECK(simplex_is_changed); + BOOST_CHECK(st.num_simplices() == 0); + + // Display the Simplex_tree + std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; + +} diff --git a/src/Simplex_tree/test/simplex_tree_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_unit_test.cpp index 17ddc605..580d610a 100644 --- a/src/Simplex_tree/test/simplex_tree_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_unit_test.cpp @@ -297,6 +297,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_tree_insertion, typeST, list_of_tested_var // Simplex_handle = boost::container::flat_map< typeST::Vertex_handle, Node >::iterator typename typeST::Simplex_handle shReturned = returnValue.first; BOOST_CHECK(shReturned == typename typeST::Simplex_handle(nullptr)); + std::cout << "st.num_vertices()=" << st.num_vertices() << std::endl; BOOST_CHECK(st.num_vertices() == (size_t) 4); // Not incremented !! BOOST_CHECK(st.dimension() == dim_max); @@ -617,9 +618,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(coface_on_simplex_tree, typeST, list_of_tested_var /* o */ /* 5 */ - // FIXME - st.set_dimension(3); - std::vector<typename typeST::Vertex_handle> simplex_result; std::vector<typename typeST::Simplex_handle> result; std::cout << "First test - Star of (3):" << std::endl; @@ -716,9 +714,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(copy_move_on_simplex_tree, typeST, list_of_tested_ /* o */ /* 5 */ - // FIXME - st.set_dimension(3); - std::cout << "Printing st - address = " << &st << std::endl; // Copy constructor @@ -868,271 +863,3 @@ BOOST_AUTO_TEST_CASE(make_filtration_non_decreasing) { BOOST_CHECK(st == st_other_copy); } - -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; -}; - -BOOST_AUTO_TEST_CASE(remove_maximal_simplex) { - std::cout << "********************************************************************" << std::endl; - std::cout << "REMOVE MAXIMAL SIMPLEX" << std::endl; - - - typedef Simplex_tree<MyOptions> miniST; - miniST st; - - // FIXME - st.set_dimension(3); - - st.insert_simplex_and_subfaces({0, 1, 6, 7}); - st.insert_simplex_and_subfaces({3, 4, 5}); - - // Constructs a copy at this state for further test purpose - miniST st_pruned = st; - - st.insert_simplex_and_subfaces({3, 0}); - st.insert_simplex_and_subfaces({2, 1, 0}); - - // Constructs a copy at this state for further test purpose - miniST st_complete = st; - // st_complete and st: - // 1 6 - // o---o - // /X\7/ - // o---o---o---o - // 2 0 3\X/4 - // o - // 5 - // st_pruned: - // 1 6 - // o---o - // \7/ - // o o---o - // 0 3\X/4 - // o - // 5 - -#ifdef GUDHI_DEBUG - std::cout << "Check exception throw in debug mode" << std::endl; - // throw excpt because sh has children - BOOST_CHECK_THROW (st.remove_maximal_simplex(st.find({0, 1, 6})), std::invalid_argument); - BOOST_CHECK_THROW (st.remove_maximal_simplex(st.find({3})), std::invalid_argument); - BOOST_CHECK(st == st_complete); -#endif - - st.remove_maximal_simplex(st.find({0, 2})); - st.remove_maximal_simplex(st.find({0, 1, 2})); - st.remove_maximal_simplex(st.find({1, 2})); - st.remove_maximal_simplex(st.find({2})); - st.remove_maximal_simplex(st.find({0, 3})); - - BOOST_CHECK(st == st_pruned); - // Remove all, but as the simplex tree is not storing filtration, there is no modification - st.prune_above_filtration(0.0); - BOOST_CHECK(st == st_pruned); - - miniST st_wo_seven; - // FIXME - st_wo_seven.set_dimension(3); - - st_wo_seven.insert_simplex_and_subfaces({0, 1, 6}); - st_wo_seven.insert_simplex_and_subfaces({3, 4, 5}); - // st_wo_seven: - // 1 6 - // o---o - // \X/ - // o o---o - // 0 3\X/4 - // o - // 5 - - // Remove all 7 to test the both remove_maximal_simplex cases (when _members is empty or not) - st.remove_maximal_simplex(st.find({0, 1, 6, 7})); - st.remove_maximal_simplex(st.find({0, 1, 7})); - st.remove_maximal_simplex(st.find({0, 6, 7})); - st.remove_maximal_simplex(st.find({0, 7})); - st.remove_maximal_simplex(st.find({1, 6, 7})); - st.remove_maximal_simplex(st.find({1, 7})); - st.remove_maximal_simplex(st.find({6, 7})); - st.remove_maximal_simplex(st.find({7})); - - BOOST_CHECK(st == st_wo_seven); -} - -BOOST_AUTO_TEST_CASE(prune_above_filtration) { - std::cout << "********************************************************************" << std::endl; - std::cout << "PRUNE ABOVE FILTRATION" << std::endl; - typedef Simplex_tree<> typeST; - typeST st; - - // FIXME - st.set_dimension(3); - - st.insert_simplex_and_subfaces({0, 1, 6, 7}, 1.0); - st.insert_simplex_and_subfaces({3, 4, 5}, 2.0); - - // Constructs a copy at this state for further test purpose - typeST st_pruned = st; - st_pruned.initialize_filtration(); // reset - - st.insert_simplex_and_subfaces({3, 0}, 3.0); - st.insert_simplex_and_subfaces({2, 1, 0}, 4.0); - - // Constructs a copy at this state for further test purpose - typeST st_complete = st; - // st_complete and st: - // 1 6 - // o---o - // /X\7/ - // o---o---o---o - // 2 0 3\X/4 - // o - // 5 - // st_pruned: - // 1 6 - // o---o - // \7/ - // o o---o - // 0 3\X/4 - // o - // 5 - - bool simplex_is_changed = false; - // Check the no action cases - // greater than initial filtration value - simplex_is_changed = st.prune_above_filtration(10.0); - if (simplex_is_changed) - st.initialize_filtration(); - BOOST_CHECK(st == st_complete); - BOOST_CHECK(!simplex_is_changed); - // equal to initial filtration value - simplex_is_changed = st.prune_above_filtration(6.0); - if (simplex_is_changed) - st.initialize_filtration(); - BOOST_CHECK(st == st_complete); - BOOST_CHECK(!simplex_is_changed); - // lower than initial filtration value, but still greater than the maximum filtration value - simplex_is_changed = st.prune_above_filtration(5.0); - if (simplex_is_changed) - st.initialize_filtration(); - BOOST_CHECK(st == st_complete); - BOOST_CHECK(!simplex_is_changed); - - // Display the Simplex_tree - std::cout << "The complex contains " << st.num_simplices() << " simplices"; - std::cout << " - dimension " << st.dimension() << 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 << (int) vertex << " "; - } - std::cout << std::endl; - } - - // Check the pruned cases - simplex_is_changed = st.prune_above_filtration(2.5); - if (simplex_is_changed) - st.initialize_filtration(); - BOOST_CHECK(st == st_pruned); - BOOST_CHECK(simplex_is_changed); - - // Display the Simplex_tree - std::cout << "The complex pruned at 2.5 contains " << st.num_simplices() << " simplices"; - std::cout << " - dimension " << st.dimension() << std::endl; - - simplex_is_changed = st.prune_above_filtration(2.0); - if (simplex_is_changed) - st.initialize_filtration(); - - std::cout << "The complex pruned at 2.0 contains " << st.num_simplices() << " simplices"; - std::cout << " - dimension " << st.dimension() << std::endl; - - BOOST_CHECK(st == st_pruned); - BOOST_CHECK(!simplex_is_changed); - - typeST st_empty; - // FIXME - st_empty.set_dimension(3); - simplex_is_changed = st.prune_above_filtration(0.0); - if (simplex_is_changed) - st.initialize_filtration(); - - // Display the Simplex_tree - std::cout << "The complex pruned at 0.0 contains " << st.num_simplices() << " simplices"; - std::cout << " - dimension " << st.dimension() << std::endl; - - BOOST_CHECK(st == st_empty); - BOOST_CHECK(simplex_is_changed); - - // Test case to the limit - simplex_is_changed = st.prune_above_filtration(-1.0); - if (simplex_is_changed) - st.initialize_filtration(); - BOOST_CHECK(st == st_empty); - BOOST_CHECK(!simplex_is_changed); -} - -BOOST_AUTO_TEST_CASE(mini_prune_above_filtration) { - std::cout << "********************************************************************" << std::endl; - std::cout << "MINI PRUNE ABOVE FILTRATION" << std::endl; - typedef Simplex_tree<MyOptions> typeST; - typeST st; - - // FIXME - st.set_dimension(3); - - st.insert_simplex_and_subfaces({0, 1, 6, 7}); - st.insert_simplex_and_subfaces({3, 4, 5}); - st.insert_simplex_and_subfaces({3, 0}); - st.insert_simplex_and_subfaces({2, 1, 0}); - - // st: - // 1 6 - // o---o - // /X\7/ - // o---o---o---o - // 2 0 3\X/4 - // o - // 5 - - st.initialize_filtration(); - - // Display the Simplex_tree - std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; - BOOST_CHECK(st.num_simplices() == 27); - - // Test case to the limit - With these options, there is no filtration, which means filtration is 0 - bool simplex_is_changed = st.prune_above_filtration(1.0); - if (simplex_is_changed) - st.initialize_filtration(); - // Display the Simplex_tree - std::cout << "The complex pruned at 1.0 contains " << st.num_simplices() << " simplices" << std::endl; - BOOST_CHECK(!simplex_is_changed); - BOOST_CHECK(st.num_simplices() == 27); - - simplex_is_changed = st.prune_above_filtration(0.0); - if (simplex_is_changed) - st.initialize_filtration(); - // Display the Simplex_tree - std::cout << "The complex pruned at 0.0 contains " << st.num_simplices() << " simplices" << std::endl; - BOOST_CHECK(!simplex_is_changed); - BOOST_CHECK(st.num_simplices() == 27); - - // Test case to the limit - simplex_is_changed = st.prune_above_filtration(-1.0); - if (simplex_is_changed) - st.initialize_filtration(); - // Display the Simplex_tree - std::cout << "The complex pruned at -1.0 contains " << st.num_simplices() << " simplices" << std::endl; - BOOST_CHECK(simplex_is_changed); - BOOST_CHECK(st.num_simplices() == 0); - - // Display the Simplex_tree - std::cout << "The complex contains " << st.num_simplices() << " simplices" << std::endl; - -} diff --git a/src/Spatial_searching/doc/Intro_spatial_searching.h b/src/Spatial_searching/doc/Intro_spatial_searching.h index 22652ac4..1ee5e92e 100644 --- a/src/Spatial_searching/doc/Intro_spatial_searching.h +++ b/src/Spatial_searching/doc/Intro_spatial_searching.h @@ -46,7 +46,7 @@ namespace spatial_searching { * * \section spatial_searching_examples Example * - * This example generates 500 random points, then performs near search, and queries for nearest and farthest points using different methods. + * This example generates 500 random points, then performs all-near-neighbors searches, and queries for nearest and furthest neighbors using different methods. * * \include Spatial_searching/example_spatial_searching.cpp * diff --git a/src/Spatial_searching/example/example_spatial_searching.cpp b/src/Spatial_searching/example/example_spatial_searching.cpp index 201b589e..034ad24a 100644 --- a/src/Spatial_searching/example/example_spatial_searching.cpp +++ b/src/Spatial_searching/example/example_spatial_searching.cpp @@ -24,34 +24,34 @@ int main(void) { // 10-nearest neighbor query std::cout << "10 nearest neighbors from points[20]:\n"; - auto knn_range = points_ds.query_k_nearest_neighbors(points[20], 10, true); + auto knn_range = points_ds.k_nearest_neighbors(points[20], 10, true); for (auto const& nghb : knn_range) std::cout << nghb.first << " (sq. dist. = " << nghb.second << ")\n"; // Incremental nearest neighbor query std::cout << "Incremental nearest neighbors:\n"; - auto inn_range = points_ds.query_incremental_nearest_neighbors(points[45]); + auto inn_range = points_ds.incremental_nearest_neighbors(points[45]); // Get the neighbors in distance order until we hit the first point for (auto ins_iterator = inn_range.begin(); ins_iterator->first != 0; ++ins_iterator) std::cout << ins_iterator->first << " (sq. dist. = " << ins_iterator->second << ")\n"; - // 10-farthest neighbor query - std::cout << "10 farthest neighbors from points[20]:\n"; - auto kfn_range = points_ds.query_k_farthest_neighbors(points[20], 10, true); + // 10-furthest neighbor query + std::cout << "10 furthest neighbors from points[20]:\n"; + auto kfn_range = points_ds.k_furthest_neighbors(points[20], 10, true); for (auto const& nghb : kfn_range) std::cout << nghb.first << " (sq. dist. = " << nghb.second << ")\n"; - // Incremental farthest neighbor query - std::cout << "Incremental farthest neighbors:\n"; - auto ifn_range = points_ds.query_incremental_farthest_neighbors(points[45]); + // Incremental furthest neighbor query + std::cout << "Incremental furthest neighbors:\n"; + auto ifn_range = points_ds.incremental_furthest_neighbors(points[45]); // Get the neighbors in distance reverse order until we hit the first point for (auto ifs_iterator = ifn_range.begin(); ifs_iterator->first != 0; ++ifs_iterator) std::cout << ifs_iterator->first << " (sq. dist. = " << ifs_iterator->second << ")\n"; - // Near search - std::cout << "Near search:\n"; + // All-near-neighbors search + std::cout << "All-near-neighbors search:\n"; std::vector<std::size_t> rs_result; - points_ds.near_search(points[45], 0.5, std::back_inserter(rs_result)); + points_ds.all_near_neighbors(points[45], 0.5, std::back_inserter(rs_result)); K k; for (auto const& p_idx : rs_result) std::cout << p_idx << " (sq. dist. = " << k.squared_distance_d_object()(points[p_idx], points[45]) << ")\n"; diff --git a/src/Spatial_searching/include/gudhi/Kd_tree_search.h b/src/Spatial_searching/include/gudhi/Kd_tree_search.h index af04736b..ef428002 100644 --- a/src/Spatial_searching/include/gudhi/Kd_tree_search.h +++ b/src/Spatial_searching/include/gudhi/Kd_tree_search.h @@ -42,19 +42,19 @@ namespace spatial_searching { /** * \class Kd_tree_search Kd_tree_search.h gudhi/Kd_tree_search.h - * \brief Spatial tree data structure to perform (approximate) nearest and farthest neighbor search. + * \brief Spatial tree data structure to perform (approximate) nearest and furthest neighbor search. * * \ingroup spatial_searching * * \details * The class Kd_tree_search is a tree-based data structure, based on * <a target="_blank" href="http://doc.cgal.org/latest/Spatial_searching/index.html">CGAL dD spatial searching data structures</a>. - * It provides a simplified API to perform (approximate) nearest and farthest neighbor searches. Contrary to CGAL default behavior, the tree + * It provides a simplified API to perform (approximate) nearest and furthest neighbor searches. Contrary to CGAL default behavior, the tree * does not store the points themselves, but stores indices. * - * There are two types of queries: the <i>k-nearest or k-farthest neighbor query</i>, where <i>k</i> is fixed and the <i>k</i> nearest - * or farthest points are computed right away, - * and the <i>incremental nearest or farthest neighbor query</i>, where no number of neighbors is provided during the call, as the + * There are two types of queries: the <i>k-nearest or k-furthest neighbor query</i>, where <i>k</i> is fixed and the <i>k</i> nearest + * or furthest points are computed right away, + * and the <i>incremental nearest or furthest neighbor query</i>, where no number of neighbors is provided during the call, as the * neighbors will be computed incrementally when the iterator on the range is incremented. * * \tparam Search_traits must be a model of the <a target="_blank" @@ -96,7 +96,7 @@ class Kd_tree_search { typedef CGAL::Orthogonal_k_neighbor_search<STraits> K_neighbor_search; typedef typename K_neighbor_search::Tree Tree; typedef typename K_neighbor_search::Distance Distance; - /// \brief The range returned by a k-nearest or k-farthest neighbor search. + /// \brief The range returned by a k-nearest or k-furthest neighbor search. /// Its value type is `std::pair<std::size_t, FT>` where `first` is the index /// of a point P and `second` is the squared distance between P and the query point. typedef K_neighbor_search KNS_range; @@ -104,7 +104,7 @@ class Kd_tree_search { typedef CGAL::Orthogonal_incremental_neighbor_search< STraits, Distance, CGAL::Sliding_midpoint<STraits>, Tree> Incremental_neighbor_search; - /// \brief The range returned by an incremental nearest or farthest neighbor search. + /// \brief The range returned by an incremental nearest or furthest neighbor search. /// Its value type is `std::pair<std::size_t, FT>` where `first` is the index /// of a point P and `second` is the squared distance between P and the query point. typedef Incremental_neighbor_search INS_range; @@ -171,7 +171,7 @@ class Kd_tree_search { /// @param[in] sorted Indicates if the computed sequence of k-nearest neighbors needs to be sorted. /// @param[in] eps Approximation factor. /// @return A range (whose `value_type` is `std::size_t`) containing the k-nearest neighbors. - KNS_range query_k_nearest_neighbors( + KNS_range k_nearest_neighbors( Point const& p, unsigned int k, bool sorted = true, @@ -197,7 +197,7 @@ class Kd_tree_search { /// neighbors sorted by their distance to p. /// All the neighbors are not computed by this function, but they will be /// computed incrementally when the iterator on the range is incremented. - INS_range query_incremental_nearest_neighbors(Point const& p, FT eps = FT(0)) const { + INS_range incremental_nearest_neighbors(Point const& p, FT eps = FT(0)) const { // Initialize the search structure, and search all N points // Note that we need to pass the Distance explicitly since it needs to // know the property map @@ -211,13 +211,13 @@ class Kd_tree_search { return search; } - /// \brief Search for the k-farthest points from a query point. + /// \brief Search for the k-furthest points from a query point. /// @param[in] p The query point. - /// @param[in] k Number of farthest points to search. - /// @param[in] sorted Indicates if the computed sequence of k-farthest neighbors needs to be sorted. + /// @param[in] k Number of furthest points to search. + /// @param[in] sorted Indicates if the computed sequence of k-furthest neighbors needs to be sorted. /// @param[in] eps Approximation factor. - /// @return A range (whose `value_type` is `std::size_t`) containing the k-farthest neighbors. - KNS_range query_k_farthest_neighbors( + /// @return A range (whose `value_type` is `std::size_t`) containing the k-furthest neighbors. + KNS_range k_furthest_neighbors( Point const& p, unsigned int k, bool sorted = true, @@ -236,14 +236,14 @@ class Kd_tree_search { return search; } - /// \brief Search incrementally for the farthest neighbors from a query point. + /// \brief Search incrementally for the furthest neighbors from a query point. /// @param[in] p The query point. /// @param[in] eps Approximation factor. /// @return A range (whose `value_type` is `std::size_t`) /// containing the neighbors sorted by their distance to p. /// All the neighbors are not computed by this function, but they will be /// computed incrementally when the iterator on the range is incremented. - INS_range query_incremental_farthest_neighbors(Point const& p, FT eps = FT(0)) const { + INS_range incremental_furthest_neighbors(Point const& p, FT eps = FT(0)) const { // Initialize the search structure, and search all N points // Note that we need to pass the Distance explicitly since it needs to // know the property map @@ -264,7 +264,7 @@ class Kd_tree_search { /// Note: `it` is used this way: `*it++ = each_point`. /// @param[in] eps Approximation factor. template <typename OutputIterator> - void near_search(Point const& p, + void all_near_neighbors(Point const& p, FT radius, OutputIterator it, FT eps = FT(0)) const { diff --git a/src/Spatial_searching/test/test_Kd_tree_search.cpp b/src/Spatial_searching/test/test_Kd_tree_search.cpp index 663a103a..8a8334c3 100644 --- a/src/Spatial_searching/test/test_Kd_tree_search.cpp +++ b/src/Spatial_searching/test/test_Kd_tree_search.cpp @@ -48,12 +48,12 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { Points_ds points_ds(points); - // Test query_k_nearest_neighbors + // Test k_nearest_neighbors std::size_t closest_pt_index = - points_ds.query_k_nearest_neighbors(points[10], 1, false).begin()->first; + points_ds.k_nearest_neighbors(points[10], 1, false).begin()->first; BOOST_CHECK(closest_pt_index == 10); - auto kns_range = points_ds.query_k_nearest_neighbors(points[20], 10, true); + auto kns_range = points_ds.k_nearest_neighbors(points[20], 10, true); std::vector<std::size_t> knn_result; FT last_dist = -1.; @@ -63,12 +63,12 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { last_dist = nghb.second; } - // Test query_incremental_nearest_neighbors + // Test incremental_nearest_neighbors closest_pt_index = - points_ds.query_incremental_nearest_neighbors(points[10]).begin()->first; + points_ds.incremental_nearest_neighbors(points[10]).begin()->first; BOOST_CHECK(closest_pt_index == 10); - auto inn_range = points_ds.query_incremental_nearest_neighbors(points[20]); + auto inn_range = points_ds.incremental_nearest_neighbors(points[20]); std::vector<std::size_t> inn_result; last_dist = -1.; @@ -83,8 +83,8 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { // Same result for KNN and INN? BOOST_CHECK(knn_result == inn_result); - // Test query_k_farthest_neighbors - auto kfn_range = points_ds.query_k_farthest_neighbors(points[20], 10, true); + // Test k_furthest_neighbors + auto kfn_range = points_ds.k_furthest_neighbors(points[20], 10, true); std::vector<std::size_t> kfn_result; last_dist = kfn_range.begin()->second; @@ -94,8 +94,8 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { last_dist = nghb.second; } - // Test query_k_farthest_neighbors - auto ifn_range = points_ds.query_incremental_farthest_neighbors(points[20]); + // Test k_furthest_neighbors + auto ifn_range = points_ds.incremental_furthest_neighbors(points[20]); std::vector<std::size_t> ifn_result; last_dist = ifn_range.begin()->second; @@ -110,10 +110,10 @@ BOOST_AUTO_TEST_CASE(test_Kd_tree_search) { // Same result for KFN and IFN? BOOST_CHECK(kfn_result == ifn_result); - // Test near search + // Test all_near_neighbors Point rs_q(rd.get_double(-1., 1), rd.get_double(-1., 1), rd.get_double(-1., 1), rd.get_double(-1., 1)); std::vector<std::size_t> rs_result; - points_ds.near_search(rs_q, 0.5, std::back_inserter(rs_result)); + points_ds.all_near_neighbors(rs_q, 0.5, std::back_inserter(rs_result)); K k; for (auto const& p_idx : rs_result) BOOST_CHECK(k.squared_distance_d_object()(points[p_idx], rs_q) <= 0.5); diff --git a/src/Subsampling/include/gudhi/sparsify_point_set.h b/src/Subsampling/include/gudhi/sparsify_point_set.h index 507f8c79..7d3b97fb 100644 --- a/src/Subsampling/include/gudhi/sparsify_point_set.h +++ b/src/Subsampling/include/gudhi/sparsify_point_set.h @@ -83,7 +83,7 @@ sparsify_point_set( *output_it++ = *it_pt; - auto ins_range = points_ds.query_incremental_nearest_neighbors(*it_pt); + auto ins_range = points_ds.incremental_nearest_neighbors(*it_pt); // If another point Q is closer that min_squared_dist, mark Q to be dropped for (auto const& neighbor : ins_range) { diff --git a/src/Tangential_complex/include/gudhi/Tangential_complex.h b/src/Tangential_complex/include/gudhi/Tangential_complex.h index 9fa7c825..6f061922 100644 --- a/src/Tangential_complex/include/gudhi/Tangential_complex.h +++ b/src/Tangential_complex/include/gudhi/Tangential_complex.h @@ -155,7 +155,7 @@ class Tangential_complex { >::type Triangulation; typedef typename Triangulation::Geom_traits Tr_traits; typedef typename Triangulation::Weighted_point Tr_point; - typedef typename Triangulation::Bare_point Tr_bare_point; + typedef typename Tr_traits::Base::Point_d Tr_bare_point; typedef typename Triangulation::Vertex_handle Tr_vertex_handle; typedef typename Triangulation::Full_cell_handle Tr_full_cell_handle; typedef typename Tr_traits::Vector_d Tr_vector; @@ -1093,8 +1093,8 @@ class Tangential_complex { std::size_t num_inserted_points = 1; #endif // const int NUM_NEIGHBORS = 150; - // KNS_range ins_range = m_points_ds.query_k_nearest_neighbors(center_pt, NUM_NEIGHBORS); - INS_range ins_range = m_points_ds.query_incremental_nearest_neighbors(center_pt); + // KNS_range ins_range = m_points_ds.k_nearest_neighbors(center_pt, NUM_NEIGHBORS); + INS_range ins_range = m_points_ds.incremental_nearest_neighbors(center_pt); // While building the local triangulation, we keep the radius // of the sphere "star sphere" centered at "center_vertex" @@ -1203,7 +1203,7 @@ class Tangential_complex { Point center_point = compute_perturbed_point(i); // Among updated point, what is the closer from our center point? std::size_t closest_pt_index = - updated_pts_ds.query_k_nearest_neighbors(center_point, 1, false).begin()->first; + updated_pts_ds.k_nearest_neighbors(center_point, 1, false).begin()->first; typename K::Construct_weighted_point_d k_constr_wp = m_k.construct_weighted_point_d_object(); @@ -1315,11 +1315,10 @@ class Tangential_complex { m_k.compute_coordinate_d_object(); #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM - KNS_range kns_range = m_points_ds_for_tse.query_k_nearest_neighbors( - p, num_pts_for_pca, false); + KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca, false); const Points &points_for_pca = m_points_for_tse; #else - KNS_range kns_range = m_points_ds.query_k_nearest_neighbors(p, num_pts_for_pca, false); + KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca, false); const Points &points_for_pca = m_points; #endif @@ -1413,11 +1412,10 @@ class Tangential_complex { const Point &p = m_points[*it_index]; #ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM - KNS_range kns_range = m_points_ds_for_tse.query_k_nearest_neighbors( - p, num_pts_for_pca, false); + KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca, false); const Points &points_for_pca = m_points_for_tse; #else - KNS_range kns_range = m_points_ds.query_k_nearest_neighbors(p, num_pts_for_pca, false); + KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca, false); const Points &points_for_pca = m_points; #endif diff --git a/src/Witness_complex/include/gudhi/Euclidean_strong_witness_complex.h b/src/Witness_complex/include/gudhi/Euclidean_strong_witness_complex.h index fb669ef8..4f3cef4f 100644 --- a/src/Witness_complex/include/gudhi/Euclidean_strong_witness_complex.h +++ b/src/Witness_complex/include/gudhi/Euclidean_strong_witness_complex.h @@ -84,7 +84,7 @@ class Euclidean_strong_witness_complex : landmarks_(std::begin(landmarks), std::end(landmarks)), landmark_tree_(landmarks_) { nearest_landmark_table_.reserve(boost::size(witnesses)); for (auto w : witnesses) - nearest_landmark_table_.push_back(landmark_tree_.query_incremental_nearest_neighbors(w)); + nearest_landmark_table_.push_back(landmark_tree_.incremental_nearest_neighbors(w)); } /** \brief Returns the point corresponding to the given vertex. diff --git a/src/Witness_complex/include/gudhi/Euclidean_witness_complex.h b/src/Witness_complex/include/gudhi/Euclidean_witness_complex.h index 6afe9a5d..ff8bb139 100644 --- a/src/Witness_complex/include/gudhi/Euclidean_witness_complex.h +++ b/src/Witness_complex/include/gudhi/Euclidean_witness_complex.h @@ -86,7 +86,7 @@ class Euclidean_witness_complex : landmarks_(std::begin(landmarks), std::end(landmarks)), landmark_tree_(landmarks) { nearest_landmark_table_.reserve(boost::size(witnesses)); for (auto w : witnesses) - nearest_landmark_table_.push_back(landmark_tree_.query_incremental_nearest_neighbors(w)); + nearest_landmark_table_.push_back(landmark_tree_.incremental_nearest_neighbors(w)); } /** \brief Returns the point corresponding to the given vertex. diff --git a/src/Witness_complex/include/gudhi/Strong_witness_complex.h b/src/Witness_complex/include/gudhi/Strong_witness_complex.h index 6f4bcf60..c18335d3 100644 --- a/src/Witness_complex/include/gudhi/Strong_witness_complex.h +++ b/src/Witness_complex/include/gudhi/Strong_witness_complex.h @@ -127,7 +127,6 @@ class Strong_witness_complex { if ((Landmark_id)simplex.size() - 1 > complex_dim) complex_dim = simplex.size() - 1; } - complex.set_dimension(complex_dim); return true; } diff --git a/src/Witness_complex/include/gudhi/Witness_complex.h b/src/Witness_complex/include/gudhi/Witness_complex.h index bcfe8484..53c38520 100644 --- a/src/Witness_complex/include/gudhi/Witness_complex.h +++ b/src/Witness_complex/include/gudhi/Witness_complex.h @@ -130,7 +130,6 @@ class Witness_complex { } k++; } - complex.set_dimension(k-1); return true; } diff --git a/src/Witness_complex/test/test_euclidean_simple_witness_complex.cpp b/src/Witness_complex/test/test_euclidean_simple_witness_complex.cpp index 62fd1157..4f718203 100644 --- a/src/Witness_complex/test/test_euclidean_simple_witness_complex.cpp +++ b/src/Witness_complex/test/test_euclidean_simple_witness_complex.cpp @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(simple_witness_complex) { Kd_tree landmark_tree(landmarks); Nearest_landmark_table nearest_landmark_table; for (auto w: witnesses) - nearest_landmark_table.push_back(landmark_tree.query_incremental_nearest_neighbors(w)); + nearest_landmark_table.push_back(landmark_tree.incremental_nearest_neighbors(w)); // Weak witness complex: Euclidean version EuclideanWitnessComplex eucl_witness_complex(landmarks, diff --git a/src/cmake/modules/GUDHI_doxygen_target.cmake b/src/cmake/modules/GUDHI_doxygen_target.cmake index d2cb952d..f3e2d9f5 100644 --- a/src/cmake/modules/GUDHI_doxygen_target.cmake +++ b/src/cmake/modules/GUDHI_doxygen_target.cmake @@ -3,6 +3,11 @@ find_package(Doxygen) if(DOXYGEN_FOUND) # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) + #starting from cmake 3.9 the usage of DOXYGEN_EXECUTABLE is deprecated + if(TARGET Doxygen::doxygen) + get_property(DOXYGEN_EXECUTABLE TARGET Doxygen::doxygen PROPERTY IMPORTED_LOCATION) + endif() + add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${GUDHI_USER_VERSION_DIR}/Doxyfile WORKING_DIRECTORY ${GUDHI_USER_VERSION_DIR} DEPENDS ${GUDHI_USER_VERSION_DIR}/Doxyfile ${GUDHI_DOXYGEN_DEPENDENCY} diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index f2bbafdc..8269c3bf 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -54,10 +54,12 @@ if(CGAL_FOUND) endforeach(CGAL_INCLUDE_DIR ${CGAL_INCLUDE_DIRS}) endif(NOT CGAL_VERSION VERSION_GREATER 4.9.0) - # For dev version - include_directories(BEFORE "src/common/include/gudhi_patches") - # For user version - include_directories(BEFORE "include/gudhi_patches") + if (NOT CGAL_VERSION VERSION_GREATER 4.11.0) + # For dev version + include_directories(BEFORE "src/common/include/gudhi_patches") + # For user version + include_directories(BEFORE "include/gudhi_patches") + endif (NOT CGAL_VERSION VERSION_GREATER 4.11.0) endif() endif() diff --git a/src/cmake/modules/GUDHI_user_version_target.cmake b/src/cmake/modules/GUDHI_user_version_target.cmake index cff64ad2..4abc2574 100644 --- a/src/cmake/modules/GUDHI_user_version_target.cmake +++ b/src/cmake/modules/GUDHI_user_version_target.cmake @@ -48,7 +48,11 @@ if (NOT CMAKE_VERSION VERSION_LESS 2.8.11) copy_directory ${CMAKE_SOURCE_DIR}/src/GudhUI ${GUDHI_USER_VERSION_DIR}/GudhUI) set(GUDHI_DIRECTORIES "doc;example;concept;utilities") - set(GUDHI_INCLUDE_DIRECTORIES "include/gudhi;include/gudhi_patches") + if (NOT CGAL_VERSION VERSION_GREATER 4.11.0) + set(GUDHI_INCLUDE_DIRECTORIES "include/gudhi;include/gudhi_patches") + else () + set(GUDHI_INCLUDE_DIRECTORIES "include/gudhi") + endif () foreach(GUDHI_MODULE ${GUDHI_MODULES_FULL_LIST}) foreach(GUDHI_DIRECTORY ${GUDHI_DIRECTORIES}) diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h index 91535ee6..701ea8ff 100644 --- a/src/common/doc/main_page.h +++ b/src/common/doc/main_page.h @@ -380,6 +380,8 @@ make doxygen * Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp</a> * \li <a href="_simplex_tree_2simplex_tree_from_cliques_of_graph_8cpp-example.html"> * Simplex_tree/simplex_tree_from_cliques_of_graph.cpp</a> + * \li <a href="_simplex_tree_2graph_expansion_with_blocker_8cpp-example.html"> + * Simplex_tree/graph_expansion_with_blocker.cpp</a> * \li <a href="_persistent_cohomology_2alpha_complex_3d_persistence_8cpp-example.html"> * Persistent_cohomology/alpha_complex_3d_persistence.cpp</a> * \li <a href="_persistent_cohomology_2alpha_complex_persistence_8cpp-example.html"> @@ -470,6 +472,7 @@ make doxygen * @example Simplex_tree/simple_simplex_tree.cpp * @example Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp * @example Simplex_tree/simplex_tree_from_cliques_of_graph.cpp + * @example Simplex_tree/graph_expansion_with_blocker.cpp * @example Skeleton_blocker/Skeleton_blocker_from_simplices.cpp * @example Skeleton_blocker/Skeleton_blocker_iteration.cpp * @example Skeleton_blocker/Skeleton_blocker_link.cpp diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index ec8589f0..afca9d60 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -185,6 +185,19 @@ if(CYTHON_FOUND) add_gudhi_py_test(test_tangential_complex) + # Witness complex AND Subsampling + add_test(NAME euclidean_strong_witness_complex_diagram_persistence_from_off_file_example_py_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py" + --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2) + + add_test(NAME euclidean_witness_complex_diagram_persistence_from_off_file_example_py_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py" + --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2) + # Subsampling add_gudhi_py_test(test_subsampling) @@ -218,18 +231,6 @@ if(CYTHON_FOUND) if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) # Euclidean witness - add_test(NAME euclidean_strong_witness_complex_diagram_persistence_from_off_file_example_py_test - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" - ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py" - --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2) - - add_test(NAME euclidean_witness_complex_diagram_persistence_from_off_file_example_py_test - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" - ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py" - --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 1.0 -n 20 -d 2) - add_gudhi_py_test(test_euclidean_witness_complex) endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) diff --git a/src/cython/doc/citation.rst b/src/cython/doc/citation.rst index 6cdfb7cc..f4fdf83b 100644 --- a/src/cython/doc/citation.rst +++ b/src/cython/doc/citation.rst @@ -12,4 +12,4 @@ Manual, as well as for publications directly related to the GUDHI library. GUDHI bibtex ************ -.. literalinclude:: how_to_cite_gudhi.bib +.. literalinclude:: ../../biblio/how_to_cite_gudhi.bib diff --git a/src/cython/doc/cubical_complex_user.rst b/src/cython/doc/cubical_complex_user.rst index 36fa3ba9..2bfac62a 100644 --- a/src/cython/doc/cubical_complex_user.rst +++ b/src/cython/doc/cubical_complex_user.rst @@ -59,7 +59,7 @@ directions, allows to determine, dimension, neighborhood, boundary and coboundar :math:`C \in \mathcal{K}`. .. figure:: - img/Cubical_complex_representation.png + ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png :alt: Cubical complex. :figclass: align-center @@ -87,7 +87,7 @@ in the example below). Next, in lexicographical order, the filtration of top dim 20 4 7 6 5 in the example below). .. figure:: - img/exampleBitmap.png + ../../doc/Bitmap_cubical_complex/exampleBitmap.png :alt: Example of a input data. :figclass: align-center @@ -95,9 +95,9 @@ in the example below). Next, in lexicographical order, the filtration of top dim The input file for the following complex is: -.. literalinclude:: cubicalcomplexdoc.txt +.. literalinclude:: ../../data/bitmap/cubicalcomplexdoc.txt -.. centered:: data/bitmap/cubicalcomplexdoc.txt +.. centered:: ../../data/bitmap/cubicalcomplexdoc.txt .. testcode:: @@ -128,9 +128,9 @@ complex with periodic boundary conditions. One can also use Perseus style input conditions in a given direction, then number of top dimensional cells in this direction have to be multiplied by -1. For instance: -.. literalinclude:: periodiccubicalcomplexdoc.txt +.. literalinclude:: ../../data/bitmap/periodiccubicalcomplexdoc.txt -.. centered:: data/bitmap/periodiccubicalcomplexdoc.txt +.. centered:: ../../data/bitmap/periodiccubicalcomplexdoc.txt Indicate that we have imposed periodic boundary conditions in the direction x, but not in the direction y. diff --git a/src/cython/doc/installation.rst b/src/cython/doc/installation.rst index f98a5039..c182f176 100644 --- a/src/cython/doc/installation.rst +++ b/src/cython/doc/installation.rst @@ -68,31 +68,32 @@ The :doc:`Alpha complex </alpha_complex_user>`, C++ library which provides easy access to efficient and reliable geometric algorithms. -Having CGAL version 4.6.0 or higher installed is recommended. The procedure to -install this library according to your operating system is detailed +Having CGAL, the Computational Geometry Algorithms Library, version 4.7.0 or +higher installed is recommended. The procedure to install this library +according to your operating system is detailed `here <http://doc.cgal.org/latest/Manual/installation.html>`_. -The following examples require the Computational Geometry Algorithms Library: - -.. only:: builder_html - - * :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>` - * :download:`euclidean_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py>` - -The following example requires CGAL version ≥ 4.7.0: +The following examples requires CGAL version ≥ 4.7.0: .. only:: builder_html * :download:`alpha_complex_diagram_persistence_from_off_file_example.py <../example/alpha_complex_diagram_persistence_from_off_file_example.py>` * :download:`alpha_complex_from_points_example.py <../example/alpha_complex_from_points_example.py>` -The following example requires CGAL version ≥ 4.8.0: +The following examples requires CGAL version ≥ 4.8.0: .. only:: builder_html * :download:`bottleneck_basic_example.py <../example/bottleneck_basic_example.py>` * :download:`tangential_complex_plain_homology_from_off_file_example.py <../example/tangential_complex_plain_homology_from_off_file_example.py>` +The following examples requires CGAL version ≥ 4.8.1: + +.. only:: builder_html + + * :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>` + * :download:`euclidean_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py>` + Eigen3 ====== diff --git a/src/cython/example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py b/src/cython/example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py new file mode 100755 index 00000000..79f6df75 --- /dev/null +++ b/src/cython/example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +import gudhi +import argparse + +"""This file is part of the Gudhi Library. The Gudhi library + (Geometric Understanding in Higher Dimensions) is a generic C++ + library for computational topology. + + Author(s): Vincent Rouvreau + + Copyright (C) 2017 INRIA + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2017 INRIA" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='RipsComplex creation from ' + 'a correlation matrix read in a csv file.', + epilog='Example: ' + 'example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py ' + '-f ../data/correlation_matrix/lower_triangular_correlation_matrix.csv -e 12.0 -d 3' + '- Constructs a Rips complex with the ' + 'correlation matrix from the given csv file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-e", "--max_edge_length", type=float, default=0.5) +parser.add_argument("-d", "--max_dimension", type=int, default=1) +parser.add_argument("-b", "--band_boot", type=float, default=0.) +parser.add_argument('--no-diagram', default=False, action='store_true' , help='Flag for not to display the diagrams') + +args = parser.parse_args() + +print("#####################################################################") +print("RipsComplex creation from correlation matrix read in a csv file") + +message = "RipsComplex with max_edge_length=" + repr(args.max_edge_length) +print(message) + +correlation_matrix = gudhi.read_lower_triangular_matrix_from_csv_file(csv_file=args.file) +# Given a correlation matrix M, we compute component-wise M'[i,j] = 1-M[i,j] to get a distance matrix: +distance_matrix = [[1-correlation_matrix[i][j] for j in range(len(correlation_matrix[0]))] for i in range(len(correlation_matrix))] +rips_complex = gudhi.RipsComplex(distance_matrix=distance_matrix, max_edge_length=args.max_edge_length) +simplex_tree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) + +message = "Number of simplices=" + repr(simplex_tree.num_simplices()) +print(message) + +diag = simplex_tree.persistence() + +print("betti_numbers()=") +print(simplex_tree.betti_numbers()) + +if args.no_diagram == False: + pplot = gudhi.plot_persistence_diagram(diag, band_boot=args.band_boot) + pplot.show() diff --git a/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py b/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py index fa82a2f3..c8aac240 100755 --- a/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py +++ b/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py @@ -30,12 +30,12 @@ __copyright__ = "Copyright (C) 2016 INRIA" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='RipsComplex creation from ' - 'a distance matrix read in a OFF file.', + 'a distance matrix read in a csv file.', epilog='Example: ' 'example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py ' '-f ../data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3' '- Constructs a Rips complex with the ' - 'points from the given OFF file.') + 'distance matrix from the given csv file.') parser.add_argument("-f", "--file", type=str, required=True) parser.add_argument("-e", "--max_edge_length", type=float, default=0.5) parser.add_argument("-d", "--max_dimension", type=int, default=1) diff --git a/src/cython/example/simplex_tree_example.py b/src/cython/example/simplex_tree_example.py index 831d9da8..51a60e73 100755 --- a/src/cython/example/simplex_tree_example.py +++ b/src/cython/example/simplex_tree_example.py @@ -48,8 +48,6 @@ if st.insert([0, 1, 2], filtration=4.0): else: print("Not inserted...") -# FIXME: Remove this line -st.set_dimension(3) print("dimension=", st.dimension()) st.initialize_filtration() diff --git a/src/cython/include/Tangential_complex_interface.h b/src/cython/include/Tangential_complex_interface.h index 5e9dc0e4..ecf014b3 100644 --- a/src/cython/include/Tangential_complex_interface.h +++ b/src/cython/include/Tangential_complex_interface.h @@ -106,8 +106,6 @@ class Tangential_complex_interface { void create_simplex_tree(Simplex_tree<>* simplex_tree) { int max_dim = tangential_complex_->create_complex<Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_full_featured>>(*simplex_tree); - // FIXME - simplex_tree->set_dimension(max_dim); simplex_tree->initialize_filtration(); } diff --git a/src/cython/test/test_simplex_tree.py b/src/cython/test/test_simplex_tree.py index 4d452d7d..801d52b7 100755 --- a/src/cython/test/test_simplex_tree.py +++ b/src/cython/test/test_simplex_tree.py @@ -34,9 +34,13 @@ def test_insertion(): # insert test assert st.insert([0, 1]) == True + + assert st.dimension() == 1 + assert st.insert([0, 1, 2], filtration=4.0) == True - # FIXME: Remove this line - st.set_dimension(2) + + assert st.dimension() == 2 + assert st.num_simplices() == 7 assert st.num_vertices() == 3 @@ -86,8 +90,9 @@ def test_insertion(): assert st.find([2]) == True st.initialize_filtration() - assert st.persistence() == [(1, (4.0, float('inf'))), (0, (0.0, float('inf')))] + assert st.persistence(persistence_dim_max = True) == [(1, (4.0, float('inf'))), (0, (0.0, float('inf')))] assert st.__is_persistence_defined() == True + assert st.betti_numbers() == [1, 1] assert st.persistent_betti_numbers(-0.1, 10000.0) == [0, 0] assert st.persistent_betti_numbers(0.0, 10000.0) == [1, 0] |