From 1c1c3073e0612ee401a941008a6b13438b3429e2 Mon Sep 17 00:00:00 2001 From: vrouvrea Date: Thu, 29 Sep 2016 12:34:19 +0000 Subject: Fix doxygen Add tests git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/rips_complex_module@1589 636b058d-ea47-450e-bf9e-a15bfbe3eedb Former-commit-id: 3b03e969f43f4f41c7bca1b2de96a71688475742 --- CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + src/Doxyfile | 3 +- src/Rips_complex/doc/Intro_rips_complex.h | 17 +- src/Rips_complex/example/CMakeLists.txt | 21 +- .../example_one_skeleton_rips_from_points.cpp | 64 ++++++ .../example/example_rips_complex_from_points.cpp | 69 ------ .../example/full_skeleton_rips_points_for_doc.txt | 26 +++ .../example/one_skeleton_rips_points_for_doc.txt | 20 ++ .../example/rips_points_for_doc_12_1.txt | 20 -- .../example/rips_points_for_doc_12_3.txt | 26 --- src/Rips_complex/test/CMakeLists.txt | 24 +++ src/Rips_complex/test/README | 12 ++ src/Rips_complex/test/test_rips_complex.cpp | 231 +++++++++++++++++++++ src/cmake/modules/GUDHI_user_version_target.txt | 2 +- src/common/doc/main_page.h | 23 ++ 16 files changed, 431 insertions(+), 129 deletions(-) create mode 100644 src/Rips_complex/example/example_one_skeleton_rips_from_points.cpp delete mode 100644 src/Rips_complex/example/example_rips_complex_from_points.cpp create mode 100644 src/Rips_complex/example/full_skeleton_rips_points_for_doc.txt create mode 100644 src/Rips_complex/example/one_skeleton_rips_points_for_doc.txt delete mode 100644 src/Rips_complex/example/rips_points_for_doc_12_1.txt delete mode 100644 src/Rips_complex/example/rips_points_for_doc_12_3.txt create mode 100644 src/Rips_complex/test/CMakeLists.txt create mode 100644 src/Rips_complex/test/README create mode 100644 src/Rips_complex/test/test_rips_complex.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 89e130f4..972df204 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,7 @@ else() add_subdirectory(src/Alpha_complex/example) add_subdirectory(src/Alpha_complex/test) add_subdirectory(src/Rips_complex/example) + add_subdirectory(src/Rips_complex/test) # data points generator add_subdirectory(data/points/generator) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c7744c49..7973ae39 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,6 +108,7 @@ else() add_subdirectory(example/Bitmap_cubical_complex) add_subdirectory(example/Witness_complex) add_subdirectory(example/Alpha_complex) + add_subdirectory(example/Rips_complex) # data points generator add_subdirectory(data/points/generator) diff --git a/src/Doxyfile b/src/Doxyfile index dd9a33fb..40d07049 100644 --- a/src/Doxyfile +++ b/src/Doxyfile @@ -845,7 +845,8 @@ IMAGE_PATH = doc/Skeleton_blocker/ \ doc/Simplex_tree/ \ doc/Persistent_cohomology/ \ doc/Witness_complex/ \ - doc/Bitmap_cubical_complex/ + doc/Bitmap_cubical_complex/ \ + doc/Rips_complex/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/src/Rips_complex/doc/Intro_rips_complex.h b/src/Rips_complex/doc/Intro_rips_complex.h index 85108168..bd9f5fad 100644 --- a/src/Rips_complex/doc/Intro_rips_complex.h +++ b/src/Rips_complex/doc/Intro_rips_complex.h @@ -29,11 +29,11 @@ namespace rips_complex { /** \defgroup rips_complex Rips complex * - * \author Clément Maria & Vincent Rouvreau + * \author Clément Maria and Vincent Rouvreau * * @{ * - * \section definition Definition + * \section ripsdefinition Definition * * Rips_complex * (Wikipedia) is a @@ -61,18 +61,19 @@ namespace rips_complex { * * Then, it is asked to display information about the simplicial complex. * - * \include Rips_complex/example_rips_complex_from_points.cpp + * \include Rips_complex/example_one_skeleton_rips_from_points.cpp * - * When launching: + * When launching (rips maximal distance between 2 points is 12.0, is expanded until dimension 1 - one skeleton graph + * with other words): * - * \code $> ./ripspoints + * \code $> ./oneskeletonripspoints 12.0 * \endcode * * the program output is: * - * \include Rips_complex/rips_points_for_doc_12_2.txt + * \include Rips_complex/one_skeleton_rips_points_for_doc.txt * - * \section offexample Example from OFF file + * \section ripsoffexample Example from OFF file * * This example builds the one skeleton graph from the given points in an OFF file, threshold value, and distance * function. @@ -90,7 +91,7 @@ namespace rips_complex { * * the program output is: * - * \include Rips_complex/rips_points_for_doc_12_3.txt + * \include Rips_complex/full_skeleton_rips_points_for_doc.txt * * \copyright GNU General Public License v3. * \verbatim Contact: gudhi-users@lists.gforge.inria.fr \endverbatim diff --git a/src/Rips_complex/example/CMakeLists.txt b/src/Rips_complex/example/CMakeLists.txt index f8dcf94d..3962b15e 100644 --- a/src/Rips_complex/example/CMakeLists.txt +++ b/src/Rips_complex/example/CMakeLists.txt @@ -3,12 +3,25 @@ project(Rips_complex_examples) add_executable ( ripsoffreader example_rips_complex_from_off_file.cpp ) target_link_libraries(ripsoffreader ${Boost_SYSTEM_LIBRARY}) + +add_executable ( oneskeletonripspoints example_one_skeleton_rips_from_points.cpp ) +target_link_libraries(oneskeletonripspoints ${Boost_SYSTEM_LIBRARY}) + if (TBB_FOUND) target_link_libraries(ripsoffreader ${TBB_LIBRARIES}) + target_link_libraries(oneskeletonripspoints ${TBB_LIBRARIES}) endif() -add_executable ( ripspoints example_rips_complex_from_points.cpp ) -target_link_libraries(ripspoints ${Boost_SYSTEM_LIBRARY}) -if (TBB_FOUND) - target_link_libraries(ripspoints ${TBB_LIBRARIES}) +add_test(oneskeletonripspoints ${CMAKE_CURRENT_BINARY_DIR}/oneskeletonripspoints 12.0) +# Do not forget to copy test files in current binary dir +file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) +add_test(ripsoffreader_doc_12_1 ${CMAKE_CURRENT_BINARY_DIR}/ripsoffreader alphacomplexdoc.off 12.0 1 ${CMAKE_CURRENT_BINARY_DIR}/ripsoffreader_result_12_1.txt) +add_test(ripsoffreader_doc_12_3 ${CMAKE_CURRENT_BINARY_DIR}/ripsoffreader alphacomplexdoc.off 12.0 3 ${CMAKE_CURRENT_BINARY_DIR}/ripsoffreader_result_12_3.txt) +if (DIFF_PATH) + # Do not forget to copy test results files in current binary dir + file(COPY "one_skeleton_rips_points_for_doc.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + file(COPY "full_skeleton_rips_points_for_doc.txt" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + + add_test(ripsoffreader_doc_12_1_diff_files ${DIFF_PATH} ${CMAKE_CURRENT_BINARY_DIR}/ripsoffreader_result_12_1.txt ${CMAKE_CURRENT_BINARY_DIR}/one_skeleton_rips_points_for_doc.txt) + add_test(ripsoffreader_doc_12_3_diff_files ${DIFF_PATH} ${CMAKE_CURRENT_BINARY_DIR}/ripsoffreader_result_12_3.txt ${CMAKE_CURRENT_BINARY_DIR}/full_skeleton_rips_points_for_doc.txt) endif() diff --git a/src/Rips_complex/example/example_one_skeleton_rips_from_points.cpp b/src/Rips_complex/example/example_one_skeleton_rips_from_points.cpp new file mode 100644 index 00000000..db41b425 --- /dev/null +++ b/src/Rips_complex/example/example_one_skeleton_rips_from_points.cpp @@ -0,0 +1,64 @@ +#include +// to construct Rips_complex from a OFF file of points +#include +// to construct a simplex_tree from rips complex +#include +#include + +#include +#include +#include // for std::numeric_limits + +void usage(int nbArgs, char * const progName) { + std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; + std::cerr << "Usage: " << progName << " threshold\n"; + std::cerr << " i.e.: " << progName << " 12.0\n"; + exit(-1); // ----- >> +} + +int main(int argc, char **argv) { + if (argc != 2) usage(argc, argv[0]); + + double threshold = atof(argv[1]); + + // Type definitions + using Point = std::vector; + using Simplex_tree = Gudhi::Simplex_tree<>; + using Rips_complex = Gudhi::rips_complex::Rips_complex; + + std::vector points; + points.push_back({1.0, 1.0}); + points.push_back({7.0, 0.0}); + points.push_back({4.0, 6.0}); + points.push_back({9.0, 6.0}); + points.push_back({0.0, 14.0}); + points.push_back({2.0, 19.0}); + points.push_back({9.0, 17.0}); + + // ---------------------------------------------------------------------------- + // Init of a rips complex from points + // ---------------------------------------------------------------------------- + Rips_complex rips_complex_from_file(points, threshold, euclidean_distance); + + Simplex_tree simplex; + if (rips_complex_from_file.create_complex(simplex, 1)) { + // ---------------------------------------------------------------------------- + // Display information about the one skeleton rips complex + // ---------------------------------------------------------------------------- + std::cout << "Rips complex is of dimension " << simplex.dimension() << + " - " << simplex.num_simplices() << " simplices - " << + simplex.num_vertices() << " vertices." << std::endl; + + std::cout << "Iterator on rips complex simplices in the filtration order, with [filtration value]:" << + std::endl; + for (auto f_simplex : simplex.filtration_simplex_range()) { + std::cout << " ( "; + for (auto vertex : simplex.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << ") -> " << "[" << simplex.filtration(f_simplex) << "] "; + std::cout << std::endl; + } + } + return 0; +} diff --git a/src/Rips_complex/example/example_rips_complex_from_points.cpp b/src/Rips_complex/example/example_rips_complex_from_points.cpp deleted file mode 100644 index c241d137..00000000 --- a/src/Rips_complex/example/example_rips_complex_from_points.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include -// to construct Rips_complex from a OFF file of points -#include -// to construct a simplex_tree from rips complex -#include -#include - -#include -#include -#include // for std::numeric_limits - -void usage(int nbArgs, char * const progName) { - std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; - std::cerr << "Usage: " << progName << " dim_max [threshold]\n"; - std::cerr << " i.e.: " << progName << " 3 12.0\n"; - exit(-1); // ----- >> -} - -int main(int argc, char **argv) { - if ((argc != 2) && (argc != 3)) usage(argc, argv[0]); - - double threshold = std::numeric_limits::infinity(); - int dim_max = atoi(argv[1]); - - if (argc == 3) { - threshold = atof(argv[2]); - } - - // Type definitions - using Point = std::vector; - using Simplex_tree = Gudhi::Simplex_tree<>; - using Rips_complex = Gudhi::rips_complex::Rips_complex; - - std::vector points; - points.push_back({1.0, 1.0}); - points.push_back({7.0, 0.0}); - points.push_back({4.0, 6.0}); - points.push_back({9.0, 6.0}); - points.push_back({0.0, 14.0}); - points.push_back({2.0, 19.0}); - points.push_back({9.0, 17.0}); - - // ---------------------------------------------------------------------------- - // Init of a rips complex from an OFF file - // ---------------------------------------------------------------------------- - Rips_complex rips_complex_from_file(points, threshold, euclidean_distance); - - Simplex_tree simplex; - if (rips_complex_from_file.create_complex(simplex, dim_max)) { - // ---------------------------------------------------------------------------- - // Display information about the rips complex - // ---------------------------------------------------------------------------- - std::cout << "Rips complex is of dimension " << simplex.dimension() << - " - " << simplex.num_simplices() << " simplices - " << - simplex.num_vertices() << " vertices." << std::endl; - - std::cout << "Iterator on rips complex simplices in the filtration order, with [filtration value]:" << - std::endl; - for (auto f_simplex : simplex.filtration_simplex_range()) { - std::cout << " ( "; - for (auto vertex : simplex.simplex_vertex_range(f_simplex)) { - std::cout << vertex << " "; - } - std::cout << ") -> " << "[" << simplex.filtration(f_simplex) << "] "; - std::cout << std::endl; - } - } - return 0; -} diff --git a/src/Rips_complex/example/full_skeleton_rips_points_for_doc.txt b/src/Rips_complex/example/full_skeleton_rips_points_for_doc.txt new file mode 100644 index 00000000..319931e0 --- /dev/null +++ b/src/Rips_complex/example/full_skeleton_rips_points_for_doc.txt @@ -0,0 +1,26 @@ +Rips complex is of dimension 3 - 24 simplices - 7 vertices. +Iterator on rips complex simplices in the filtration order, with [filtration value]: + ( 0 ) -> [0] + ( 1 ) -> [0] + ( 2 ) -> [0] + ( 3 ) -> [0] + ( 4 ) -> [0] + ( 5 ) -> [0] + ( 6 ) -> [0] + ( 3 2 ) -> [5] + ( 5 4 ) -> [5.38516] + ( 2 0 ) -> [5.83095] + ( 1 0 ) -> [6.08276] + ( 3 1 ) -> [6.32456] + ( 2 1 ) -> [6.7082] + ( 2 1 0 ) -> [6.7082] + ( 3 2 1 ) -> [6.7082] + ( 6 5 ) -> [7.28011] + ( 4 2 ) -> [8.94427] + ( 3 0 ) -> [9.43398] + ( 3 1 0 ) -> [9.43398] + ( 3 2 0 ) -> [9.43398] + ( 3 2 1 0 ) -> [9.43398] + ( 6 4 ) -> [9.48683] + ( 6 5 4 ) -> [9.48683] + ( 6 3 ) -> [11] diff --git a/src/Rips_complex/example/one_skeleton_rips_points_for_doc.txt b/src/Rips_complex/example/one_skeleton_rips_points_for_doc.txt new file mode 100644 index 00000000..b0e25cc5 --- /dev/null +++ b/src/Rips_complex/example/one_skeleton_rips_points_for_doc.txt @@ -0,0 +1,20 @@ +Rips complex is of dimension 1 - 18 simplices - 7 vertices. +Iterator on rips complex simplices in the filtration order, with [filtration value]: + ( 0 ) -> [0] + ( 1 ) -> [0] + ( 2 ) -> [0] + ( 3 ) -> [0] + ( 4 ) -> [0] + ( 5 ) -> [0] + ( 6 ) -> [0] + ( 3 2 ) -> [5] + ( 5 4 ) -> [5.38516] + ( 2 0 ) -> [5.83095] + ( 1 0 ) -> [6.08276] + ( 3 1 ) -> [6.32456] + ( 2 1 ) -> [6.7082] + ( 6 5 ) -> [7.28011] + ( 4 2 ) -> [8.94427] + ( 3 0 ) -> [9.43398] + ( 6 4 ) -> [9.48683] + ( 6 3 ) -> [11] diff --git a/src/Rips_complex/example/rips_points_for_doc_12_1.txt b/src/Rips_complex/example/rips_points_for_doc_12_1.txt deleted file mode 100644 index b0e25cc5..00000000 --- a/src/Rips_complex/example/rips_points_for_doc_12_1.txt +++ /dev/null @@ -1,20 +0,0 @@ -Rips complex is of dimension 1 - 18 simplices - 7 vertices. -Iterator on rips complex simplices in the filtration order, with [filtration value]: - ( 0 ) -> [0] - ( 1 ) -> [0] - ( 2 ) -> [0] - ( 3 ) -> [0] - ( 4 ) -> [0] - ( 5 ) -> [0] - ( 6 ) -> [0] - ( 3 2 ) -> [5] - ( 5 4 ) -> [5.38516] - ( 2 0 ) -> [5.83095] - ( 1 0 ) -> [6.08276] - ( 3 1 ) -> [6.32456] - ( 2 1 ) -> [6.7082] - ( 6 5 ) -> [7.28011] - ( 4 2 ) -> [8.94427] - ( 3 0 ) -> [9.43398] - ( 6 4 ) -> [9.48683] - ( 6 3 ) -> [11] diff --git a/src/Rips_complex/example/rips_points_for_doc_12_3.txt b/src/Rips_complex/example/rips_points_for_doc_12_3.txt deleted file mode 100644 index 319931e0..00000000 --- a/src/Rips_complex/example/rips_points_for_doc_12_3.txt +++ /dev/null @@ -1,26 +0,0 @@ -Rips complex is of dimension 3 - 24 simplices - 7 vertices. -Iterator on rips complex simplices in the filtration order, with [filtration value]: - ( 0 ) -> [0] - ( 1 ) -> [0] - ( 2 ) -> [0] - ( 3 ) -> [0] - ( 4 ) -> [0] - ( 5 ) -> [0] - ( 6 ) -> [0] - ( 3 2 ) -> [5] - ( 5 4 ) -> [5.38516] - ( 2 0 ) -> [5.83095] - ( 1 0 ) -> [6.08276] - ( 3 1 ) -> [6.32456] - ( 2 1 ) -> [6.7082] - ( 2 1 0 ) -> [6.7082] - ( 3 2 1 ) -> [6.7082] - ( 6 5 ) -> [7.28011] - ( 4 2 ) -> [8.94427] - ( 3 0 ) -> [9.43398] - ( 3 1 0 ) -> [9.43398] - ( 3 2 0 ) -> [9.43398] - ( 3 2 1 0 ) -> [9.43398] - ( 6 4 ) -> [9.48683] - ( 6 5 4 ) -> [9.48683] - ( 6 3 ) -> [11] diff --git a/src/Rips_complex/test/CMakeLists.txt b/src/Rips_complex/test/CMakeLists.txt new file mode 100644 index 00000000..3972e9fc --- /dev/null +++ b/src/Rips_complex/test/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 2.6) +project(Rips_complex_tests) + +if (GCOVR_PATH) + # for gcovr to make coverage reports - Corbera Jenkins plugin + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") +endif() +if (GPROF_PATH) + # for gprof to make coverage reports - Jenkins + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") +endif() + +add_executable ( rips_complex_UT test_rips_complex.cpp ) +target_link_libraries(rips_complex_UT ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +if (TBB_FOUND) + target_link_libraries(rips_complex_UT ${TBB_LIBRARIES}) +endif() + +# Do not forget to copy test files in current binary dir +file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + +add_test(rips_complex_UT ${CMAKE_CURRENT_BINARY_DIR}/rips_complex_UT + # XML format for Jenkins xUnit plugin + --log_format=XML --log_sink=${CMAKE_SOURCE_DIR}/rips_complex_UT.xml --log_level=test_suite --report_level=no) diff --git a/src/Rips_complex/test/README b/src/Rips_complex/test/README new file mode 100644 index 00000000..28236b52 --- /dev/null +++ b/src/Rips_complex/test/README @@ -0,0 +1,12 @@ +To compile: +*********** + +cmake . +make + +To launch with details: +*********************** + +./rips_complex_UT --report_level=detailed --log_level=all + + ==> echo $? returns 0 in case of success (non-zero otherwise) diff --git a/src/Rips_complex/test/test_rips_complex.cpp b/src/Rips_complex/test/test_rips_complex.cpp new file mode 100644 index 00000000..5f129160 --- /dev/null +++ b/src/Rips_complex/test/test_rips_complex.cpp @@ -0,0 +1,231 @@ +/* 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) 2016 INRIA Saclay (France) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "rips_complex" +#include + +#include // float comparison +#include +#include +#include +#include // std::max + +#include +// to construct Rips_complex from a OFF file of points +#include +// to construct a simplex_tree from rips complex +#include +#include + +// Type definitions +using Point = std::vector; +using Simplex_tree = Gudhi::Simplex_tree<>; +using Rips_complex = Gudhi::rips_complex::Rips_complex; + +bool are_almost_the_same(float a, float b) { + return std::fabs(a - b) < std::numeric_limits::epsilon(); +} + +BOOST_AUTO_TEST_CASE(RIPS_DOC_OFF_file) { + // ---------------------------------------------------------------------------- + // + // Init of a rips complex from a OFF file + // + // ---------------------------------------------------------------------------- + std::string off_file_name("alphacomplexdoc.off"); + double rips_threshold = 12.0; + std::cout << "========== OFF FILE NAME = " << off_file_name << " - rips threshold=" << + rips_threshold << "==========" << std::endl; + + Gudhi::Points_off_reader off_reader(off_file_name); + Rips_complex rips_complex_from_file(off_reader.get_point_cloud(), rips_threshold, euclidean_distance); + + const int DIMENSION_1 = 1; + Simplex_tree st; + BOOST_CHECK(rips_complex_from_file.create_complex(st, DIMENSION_1)); + std::cout << "st.dimension()=" << st.dimension() << std::endl; + BOOST_CHECK(st.dimension() == DIMENSION_1); + + const int NUMBER_OF_VERTICES = 7; + std::cout << "st.num_vertices()=" << st.num_vertices() << std::endl; + BOOST_CHECK(st.num_vertices() == NUMBER_OF_VERTICES); + + std::cout << "st.num_simplices()=" << st.num_simplices() << std::endl; + BOOST_CHECK(st.num_simplices() == 18); + + // Check filtration values of vertices is 0.0 + for (auto f_simplex : st.skeleton_simplex_range(0)) { + BOOST_CHECK(st.filtration(f_simplex) == 0.0); + } + + // Check filtration values of edges + for (auto f_simplex : st.skeleton_simplex_range(DIMENSION_1)) { + if (DIMENSION_1 == st.dimension(f_simplex)) { + std::vector vp; + std::cout << "vertex = ("; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << vertex << ","; + vp.push_back(off_reader.get_point_cloud().at(vertex)); + } + std::cout << ") - distance =" << euclidean_distance(vp.at(0), vp.at(1)) << + " - filtration =" << st.filtration(f_simplex) << std::endl; + BOOST_CHECK(vp.size() == 2); + BOOST_CHECK(are_almost_the_same(st.filtration(f_simplex), euclidean_distance(vp.at(0), vp.at(1)))); + } + } + + const int DIMENSION_2 = 2; + Simplex_tree st2; + BOOST_CHECK(rips_complex_from_file.create_complex(st2, DIMENSION_2)); + std::cout << "st2.dimension()=" << st2.dimension() << std::endl; + BOOST_CHECK(st2.dimension() == DIMENSION_2); + + std::cout << "st2.num_vertices()=" << st2.num_vertices() << std::endl; + BOOST_CHECK(st2.num_vertices() == NUMBER_OF_VERTICES); + + std::cout << "st2.num_simplices()=" << st2.num_simplices() << std::endl; + BOOST_CHECK(st2.num_simplices() == 23); + + Simplex_tree::Filtration_value f01 = st2.filtration(st2.find({0, 1})); + Simplex_tree::Filtration_value f02 = st2.filtration(st2.find({0, 2})); + Simplex_tree::Filtration_value f12 = st2.filtration(st2.find({1, 2})); + Simplex_tree::Filtration_value f012 = st2.filtration(st2.find({0, 1, 2})); + std::cout << "f012= " << f012 << " | f01= " << f01 << " - f02= " << f02 << " - f12= " << f12 << std::endl; + BOOST_CHECK(are_almost_the_same(f012, std::max(f01, std::max(f02,f12)))); + + Simplex_tree::Filtration_value f45 = st2.filtration(st2.find({4, 5})); + Simplex_tree::Filtration_value f56 = st2.filtration(st2.find({5, 6})); + Simplex_tree::Filtration_value f46 = st2.filtration(st2.find({4, 6})); + Simplex_tree::Filtration_value f456 = st2.filtration(st2.find({4, 5, 6})); + std::cout << "f456= " << f456 << " | f45= " << f45 << " - f56= " << f56 << " - f46= " << f46 << std::endl; + BOOST_CHECK(are_almost_the_same(f456, std::max(f45, std::max(f56,f46)))); + + const int DIMENSION_3 = 3; + Simplex_tree st3; + BOOST_CHECK(rips_complex_from_file.create_complex(st3, DIMENSION_3)); + std::cout << "st3.dimension()=" << st3.dimension() << std::endl; + BOOST_CHECK(st3.dimension() == DIMENSION_3); + + std::cout << "st3.num_vertices()=" << st3.num_vertices() << std::endl; + BOOST_CHECK(st3.num_vertices() == NUMBER_OF_VERTICES); + + std::cout << "st3.num_simplices()=" << st3.num_simplices() << std::endl; + BOOST_CHECK(st3.num_simplices() == 24); + + Simplex_tree::Filtration_value f123 = st3.filtration(st3.find({1, 2, 3})); + Simplex_tree::Filtration_value f013 = st3.filtration(st3.find({0, 1, 3})); + Simplex_tree::Filtration_value f023 = st3.filtration(st3.find({0, 2, 3})); + Simplex_tree::Filtration_value f0123 = st3.filtration(st3.find({0, 1, 2, 3})); + std::cout << "f0123= " << f0123 << " | f012= " << f012 << " - f123= " << f123 << " - f013= " << f013 << + " - f023= " << f023 << std::endl; + BOOST_CHECK(are_almost_the_same(f0123, std::max(f012, std::max(f123, std::max(f013, f023))))); + +} + +using Vector_of_points = std::vector; + +bool is_point_in_list(Vector_of_points points_list, Point point) { + for (auto& point_in_list : points_list) { + if (point_in_list == point) { + return true; // point found + } + } + return false; // point not found +} + +/* Compute the square value of Euclidean distance between two Points given by a range of coordinates. + * The points are assumed to have the same dimension. */ +template< typename Point > +double custom_square_euclidean_distance(const Point &p1,const Point &p2) { + double dist = 0.; + auto it1 = p1.begin(); + auto it2 = p2.begin(); + for (; it1 != p1.end(); ++it1, ++it2) { + double tmp = *it1 - *it2; + dist += tmp*tmp; + } + return dist; +} + +BOOST_AUTO_TEST_CASE(Rips_complex_from_points) { + // ---------------------------------------------------------------------------- + // Init of a list of points + // ---------------------------------------------------------------------------- + Vector_of_points points; + std::vector coords = { 0.0, 0.0, 0.0, 1.0 }; + points.push_back(Point(coords.begin(), coords.end())); + coords = { 0.0, 0.0, 1.0, 0.0 }; + points.push_back(Point(coords.begin(), coords.end())); + coords = { 0.0, 1.0, 0.0, 0.0 }; + points.push_back(Point(coords.begin(), coords.end())); + coords = { 1.0, 0.0, 0.0, 0.0 }; + points.push_back(Point(coords.begin(), coords.end())); + + // ---------------------------------------------------------------------------- + // Init of a rips complex from the list of points + // ---------------------------------------------------------------------------- + Rips_complex rips_complex_from_points(points, 2.0, custom_square_euclidean_distance); + + std::cout << "========== Rips_complex_from_points ==========" << std::endl; + Simplex_tree st; + const int DIMENSION = 3; + BOOST_CHECK(rips_complex_from_points.create_complex(st, DIMENSION)); + + // Another way to check num_simplices + std::cout << "Iterator on rips complex simplices in the filtration order, with [filtration value]:" << std::endl; + int num_simplices = 0; + for (auto f_simplex : st.filtration_simplex_range()) { + num_simplices++; + std::cout << " ( "; + for (auto vertex : st.simplex_vertex_range(f_simplex)) { + std::cout << vertex << " "; + } + std::cout << ") -> " << "[" << st.filtration(f_simplex) << "] "; + std::cout << std::endl; + } + BOOST_CHECK(num_simplices == 15); + std::cout << "st.num_simplices()=" << st.num_simplices() << std::endl; + BOOST_CHECK(st.num_simplices() == 15); + + std::cout << "st.dimension()=" << st.dimension() << std::endl; + BOOST_CHECK(st.dimension() == DIMENSION); + std::cout << "st.num_vertices()=" << st.num_vertices() << std::endl; + BOOST_CHECK(st.num_vertices() == 4); + + for (auto f_simplex : st.filtration_simplex_range()) { + std::cout << "dimension(" << st.dimension(f_simplex) << ") - f = " << st.filtration(f_simplex) << std::endl; + switch (st.dimension(f_simplex)) { + case 0: + BOOST_CHECK(are_almost_the_same(st.filtration(f_simplex), 0.0)); + break; + case 1: + case 2: + case 3: + BOOST_CHECK(are_almost_the_same(st.filtration(f_simplex), 2.0)); + break; + default: + BOOST_CHECK(false); // Shall not happen + break; + } + } +} diff --git a/src/cmake/modules/GUDHI_user_version_target.txt b/src/cmake/modules/GUDHI_user_version_target.txt index 805f0a83..78d3092f 100644 --- a/src/cmake/modules/GUDHI_user_version_target.txt +++ b/src/cmake/modules/GUDHI_user_version_target.txt @@ -48,7 +48,7 @@ if (NOT CMAKE_VERSION VERSION_LESS 2.8.11) add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/GudhUI ${GUDHI_USER_VERSION_DIR}/GudhUI) - set(GUDHI_MODULES "common;Alpha_complex;Bitmap_cubical_complex;Contraction;Hasse_complex;Persistent_cohomology;Simplex_tree;Skeleton_blocker;Witness_complex") + set(GUDHI_MODULES "common;Alpha_complex;Bitmap_cubical_complex;Contraction;Hasse_complex;Persistent_cohomology;Rips_complex;Simplex_tree;Skeleton_blocker;Witness_complex") foreach(GUDHI_MODULE ${GUDHI_MODULES}) # doc files diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h index 21cf6925..a38dbcdf 100644 --- a/src/common/doc/main_page.h +++ b/src/common/doc/main_page.h @@ -55,6 +55,23 @@ User manual: \ref cubical_complex - Reference manual: Gudhi::cubical_complex::Bitmap_cubical_complex + \subsection RipsComplexDataStructure Rips complex + \image html "rips_complex_representation.png" "Rips complex representation" + + + + + +
+ Author: Clément Maria
+ Introduced in: GUDHI 1.4.0
+ Copyright: GPL v3
+
+ Rips_complex is a simplicial complex constructed from a one skeleton graph.
+ The filtration value of each edge is computed from a user-given distance function and is inserted until a + user-given threshold value.
+ User manual: \ref rips_complex - Reference manual: Gudhi::rips_complex::Rips_complex +
\subsection SimplexTreeDataStructure Simplex tree \image html "Simplex_tree_representation.png" "Simplex tree representation" @@ -288,6 +305,10 @@ make \endverbatim * Persistent_cohomology/periodic_alpha_complex_3d_persistence.cpp * \li * Persistent_cohomology/custom_persistence_sort.cpp + * \li + * Rips_complex/example_one_skeleton_rips_from_points.cpp + * \li + * Rips_complex/example_rips_complex_from_off_file.cpp * * \section Contributions Bug reports and contributions * Please help us improving the quality of the GUDHI library. You may report bugs or suggestions to: @@ -330,6 +351,8 @@ make \endverbatim * @example Persistent_cohomology/rips_multifield_persistence.cpp * @example Persistent_cohomology/rips_persistence.cpp * @example Persistent_cohomology/custom_persistence_sort.cpp + * @example Rips_complex/example_one_skeleton_rips_from_points.cpp + * @example Rips_complex/example_rips_complex_from_off_file.cpp * @example Simplex_tree/mini_simplex_tree.cpp * @example Simplex_tree/simple_simplex_tree.cpp * @example Simplex_tree/simplex_tree_from_alpha_shapes_3.cpp -- cgit v1.2.3