diff options
author | mcarrier <mcarrier@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2018-08-28 21:20:08 +0000 |
---|---|---|
committer | mcarrier <mcarrier@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2018-08-28 21:20:08 +0000 |
commit | 421d41de2ba46670d04f4b0269c034a6be9f42bd (patch) | |
tree | a6149e5a7a9e6504800493c06e793a8fc660f3c6 /src/cython | |
parent | d34354883a5021ab9beaa03f7739378caf3e5683 (diff) | |
parent | 0784baddd1392727289a972b8374b3c2dca940a9 (diff) |
added function to read point cloud from array in memory + changed a little bit the API
git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/Nerve_GIC@3841 636b058d-ea47-450e-bf9e-a15bfbe3eedb
Former-commit-id: f31a3a60b2438d7b767a1ee310d859477330a743
Diffstat (limited to 'src/cython')
74 files changed, 1989 insertions, 468 deletions
diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index b19cc550..1849a6ec 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -1,8 +1,5 @@ -cmake_minimum_required(VERSION 2.8) project(Cython) -include(CheckCXXSourceCompiles) - function( add_gudhi_cython_lib THE_LIB ) if(EXISTS ${THE_LIB}) get_filename_component(THE_LIB_FILE_NAME ${THE_LIB} NAME_WE) @@ -19,17 +16,51 @@ endfunction( add_gudhi_cython_lib ) # THE_TEST is the python test file name (without .py extension) containing tests functions function( add_gudhi_py_test THE_TEST ) - # use ${PYTHON_EXECUTABLE} -B, otherwise a __pycache__ directory is created in sources by python - # use py.test no cache provider, otherwise a .cache file is created in sources by py.test - add_test(NAME ${THE_TEST}_py_test - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${PYTHON_EXECUTABLE} -B -m pytest -p no:cacheprovider ${CMAKE_CURRENT_SOURCE_DIR}/test/${THE_TEST}.py) + if(PYTEST_FOUND) + # use ${PYTHON_EXECUTABLE} -B, otherwise a __pycache__ directory is created in sources by python + # use py.test no cache provider, otherwise a .cache file is created in sources by py.test + add_test(NAME ${THE_TEST}_py_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${PYTHON_EXECUTABLE} -B -m pytest -p no:cacheprovider ${CMAKE_CURRENT_SOURCE_DIR}/test/${THE_TEST}.py) + endif() endfunction( add_gudhi_py_test ) +# Set gudhi.__debug_info__ +# WARNING : to be done before gudhi.pyx.in configure_file +function( add_gudhi_debug_info DEBUG_INFO ) + set(GUDHI_CYTHON_DEBUG_INFO "${GUDHI_CYTHON_DEBUG_INFO} \"${DEBUG_INFO}\\n\" \\\n" PARENT_SCOPE) +endfunction( add_gudhi_debug_info ) + if(CYTHON_FOUND) - message("++ ${PYTHON_EXECUTABLE} v.${PYTHON_VERSION_STRING} - Cython is ${CYTHON_EXECUTABLE} - Sphinx is ${SPHINX_PATH}") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}off_reader;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}simplex_tree;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}rips_complex;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}cubical_complex;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}periodic_cubical_complex;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}reader_utils;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}witness_complex;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}strong_witness_complex;") + + add_gudhi_debug_info("Python version ${PYTHON_VERSION_STRING}") + add_gudhi_debug_info("Cython version ${CYTHON_VERSION}") + if(PYTEST_FOUND) + add_gudhi_debug_info("Pytest version ${PYTEST_VERSION}") + endif() + if(MATPLOTLIB_FOUND) + add_gudhi_debug_info("Matplotlib version ${MATPLOTLIB_VERSION}") + endif() + if(NUMPY_FOUND) + add_gudhi_debug_info("Numpy version ${NUMPY_VERSION}") + endif() + if(MATPLOTLIB_FOUND AND NUMPY_FOUND) + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") + else() + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") + endif() + message("++ ${PYTHON_EXECUTABLE} v.${PYTHON_VERSION_STRING} - Cython is ${CYTHON_VERSION} - Sphinx is ${SPHINX_PATH}") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_RESULT_OF_USE_DECLTYPE', ") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_ALL_NO_LIB', ") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DBOOST_SYSTEM_NO_DEPRECATED', ") @@ -52,60 +83,63 @@ if(CYTHON_FOUND) endif() if (EIGEN3_FOUND) + add_gudhi_debug_info("Eigen3 version ${EIGEN3_VERSION}") # No problem, even if no CGAL found set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ") endif (EIGEN3_FOUND) if (NOT CGAL_VERSION VERSION_LESS 4.8.1) set(GUDHI_CYTHON_BOTTLENECK_DISTANCE "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/bottleneck_distance.pyx'") - endif (NOT CGAL_VERSION VERSION_LESS 4.8.1) + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}bottleneck_distance;") + set(GUDHI_CYTHON_NERVE_GIC "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/nerve_gic.pyx'") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}nerve_gic;") + else() + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}bottleneck_distance;") + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}nerve_gic;") + endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) set(GUDHI_CYTHON_SUBSAMPLING "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/subsampling.pyx'") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}subsampling;") set(GUDHI_CYTHON_TANGENTIAL_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/tangential_complex.pyx'") - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}tangential_complex;") + else() + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}subsampling;") + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}tangential_complex;") + endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) set(GUDHI_CYTHON_ALPHA_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/alpha_complex.pyx'") - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}alpha_complex;") + else() + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}alpha_complex;") + endif () if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) set(GUDHI_CYTHON_EUCLIDEAN_WITNESS_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/euclidean_witness_complex.pyx'\ninclude '${CMAKE_CURRENT_SOURCE_DIR}/cython/euclidean_strong_witness_complex.pyx'\n") - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}euclidean_witness_complex;") + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}euclidean_strong_witness_complex;") + else() + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}euclidean_witness_complex;") + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MISSING_MODULES}euclidean_strong_witness_complex;") + endif () + + add_gudhi_debug_info("Installed modules are: ${GUDHI_CYTHON_MODULES}") + if(GUDHI_CYTHON_MISSING_MODULES) + add_gudhi_debug_info("Missing modules are: ${GUDHI_CYTHON_MISSING_MODULES}") + endif() if(CGAL_FOUND) - # This is because of https://github.com/CGAL/cgal/blob/master/Installation/include/CGAL/tss.h - # CGAL is using boost thread if thread_local is not ready (requires XCode 8 for Mac). - # The test in https://github.com/CGAL/cgal/blob/master/Installation/include/CGAL/config.h - # #if __has_feature(cxx_thread_local) || \ - # ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ - # ( _MSC_VER >= 1900 ) - # #define CGAL_CAN_USE_CXX11_THREAD_LOCAL - # #endif - set(CGAL_CAN_USE_CXX11_THREAD_LOCAL " - int main() { - #ifndef __has_feature - #define __has_feature(x) 0 // Compatibility with non-clang compilers. - #endif - #if __has_feature(cxx_thread_local) || \ - ( (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 && __cplusplus >= 201103L ) || \ - ( _MSC_VER >= 1900 ) - bool has_feature_thread_local = true; - #else - // Explicit error of compilation for CMake test purpose - has_feature_thread_local is not defined - #endif - bool result = has_feature_thread_local; - } ") - check_cxx_source_compiles("${CGAL_CAN_USE_CXX11_THREAD_LOCAL}" CGAL_CAN_USE_CXX11_THREAD_LOCAL_RESULT) - + can_cgal_use_cxx11_thread_local() if (NOT CGAL_CAN_USE_CXX11_THREAD_LOCAL_RESULT) add_gudhi_cython_lib(${Boost_THREAD_LIBRARY}) set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ") endif() - # Add CGAL compilation args if(CGAL_HEADER_ONLY) + add_gudhi_debug_info("CGAL header only version ${CGAL_VERSION}") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_HEADER_ONLY', ") else(CGAL_HEADER_ONLY) - add_gudhi_cython_lib(${CGAL_LIBRARIES}) + add_gudhi_debug_info("CGAL version ${CGAL_VERSION}") + add_gudhi_cython_lib(${CGAL_LIBRARY}) set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${CGAL_LIBRARIES_DIR}', ") # If CGAL is not header only, CGAL library may link with boost system, add_gudhi_cython_lib(${Boost_SYSTEM_LIBRARY}) @@ -113,10 +147,12 @@ if(CYTHON_FOUND) endif(CGAL_HEADER_ONLY) # GMP and GMPXX are not required, but if present, CGAL will link with them. if(GMP_FOUND) + add_gudhi_debug_info("GMP_LIBRARIES = ${GMP_LIBRARIES}") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_USE_GMP', ") add_gudhi_cython_lib(${GMP_LIBRARIES}) set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${GMP_LIBRARIES_DIR}', ") if(GMPXX_FOUND) + add_gudhi_debug_info("GMPXX_LIBRARIES = ${GMPXX_LIBRARIES}") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_USE_GMPXX', ") add_gudhi_cython_lib(${GMPXX_LIBRARIES}) set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${GMPXX_LIBRARIES_DIR}', ") @@ -138,6 +174,7 @@ if(CYTHON_FOUND) set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${CMAKE_SOURCE_DIR}/${GUDHI_CYTHON_PATH}/include', ") if (TBB_FOUND AND WITH_GUDHI_USE_TBB) + add_gudhi_debug_info("TBB version ${TBB_INTERFACE_VERSION} found and used") set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DGUDHI_USE_TBB', ") add_gudhi_cython_lib(${TBB_RELEASE_LIBRARY}) add_gudhi_cython_lib(${TBB_MALLOC_RELEASE_LIBRARY}) @@ -178,40 +215,73 @@ if(CYTHON_FOUND) ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_rips_persistence_bottleneck_distance.py" -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -t 0.15 -d 3) - # Tangential - add_test(NAME tangential_complex_plain_homology_from_off_file_example_py_test + if(MATPLOTLIB_FOUND AND NUMPY_FOUND) + # Tangential + add_test(NAME tangential_complex_plain_homology_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/tangential_complex_plain_homology_from_off_file_example.py" + --no-diagram -i 2 -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off) + + 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) + endif() + + # Subsampling + add_gudhi_py_test(test_subsampling) + + endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + if (NOT CGAL_VERSION VERSION_LESS 4.8.1) + # Bottleneck + add_test(NAME bottleneck_basic_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/tangential_complex_plain_homology_from_off_file_example.py" - --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off) + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/bottleneck_basic_example.py") - add_gudhi_py_test(test_tangential_complex) + add_gudhi_py_test(test_bottleneck_distance) - # Witness complex AND Subsampling - add_test(NAME euclidean_strong_witness_complex_diagram_persistence_from_off_file_example_py_test + # Cover complex + file(COPY ${CMAKE_SOURCE_DIR}/data/points/human.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + file(COPY ${CMAKE_SOURCE_DIR}/data/points/COIL_database/lucky_cat.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + file(COPY ${CMAKE_SOURCE_DIR}/data/points/COIL_database/lucky_cat_PCA1 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + add_test(NAME cover_complex_nerve_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) + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/nerve_of_a_covering.py" + -f human.off -c 2 -r 10 -g 0.3) - add_test(NAME euclidean_witness_complex_diagram_persistence_from_off_file_example_py_test + add_test(NAME cover_complex_coordinate_gic_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) + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/coordinate_graph_induced_complex.py" + -f human.off -c 0 -v) - # Subsampling - add_gudhi_py_test(test_subsampling) + add_test(NAME cover_complex_functional_gic_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/functional_graph_induced_complex.py" + -o lucky_cat.off + -f lucky_cat_PCA1 -v) - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) - if (NOT CGAL_VERSION VERSION_LESS 4.8.1) - # Bottleneck - add_test(NAME bottleneck_basic_example_py_test + add_test(NAME cover_complex_voronoi_gic_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/bottleneck_basic_example.py") + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/voronoi_graph_induced_complex.py" + -f human.off -n 700 -v) - add_gudhi_py_test(test_bottleneck_distance) + add_gudhi_py_test(test_cover_complex) endif (NOT CGAL_VERSION VERSION_LESS 4.8.1) if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) @@ -221,11 +291,13 @@ if(CYTHON_FOUND) COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/alpha_complex_from_points_example.py") - add_test(NAME alpha_complex_diagram_persistence_from_off_file_example_py_test + if(MATPLOTLIB_FOUND AND NUMPY_FOUND) + add_test(NAME alpha_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/alpha_complex_diagram_persistence_from_off_file_example.py" --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -a 0.6) + endif() add_gudhi_py_test(test_alpha_complex) @@ -244,26 +316,30 @@ if(CYTHON_FOUND) ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py" --no-barcode -f ${CMAKE_SOURCE_DIR}/data/bitmap/CubicalTwoSphere.txt) - add_test(NAME random_cubical_complex_persistence_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/random_cubical_complex_persistence_example.py" - 10 10 10) + if(NUMPY_FOUND) + add_test(NAME random_cubical_complex_persistence_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/random_cubical_complex_persistence_example.py" + 10 10 10) + endif() add_gudhi_py_test(test_cubical_complex) # Rips - add_test(NAME rips_complex_diagram_persistence_from_distance_matrix_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/rips_complex_diagram_persistence_from_distance_matrix_file_example.py" - --no-diagram -f ${CMAKE_SOURCE_DIR}/data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3) - - add_test(NAME rips_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/rips_complex_diagram_persistence_from_off_file_example.py - --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -e 0.25 -d 3) + if(MATPLOTLIB_FOUND AND NUMPY_FOUND) + add_test(NAME rips_complex_diagram_persistence_from_distance_matrix_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/rips_complex_diagram_persistence_from_distance_matrix_file_example.py" + --no-diagram -f ${CMAKE_SOURCE_DIR}/data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3) + + add_test(NAME rips_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/rips_complex_diagram_persistence_from_off_file_example.py + --no-diagram -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -e 0.25 -d 3) + endif() add_test(NAME rips_complex_from_points_example_py_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} @@ -292,7 +368,7 @@ if(CYTHON_FOUND) add_gudhi_py_test(test_reader_utils) # Documentation generation is available through sphinx - requires all modules - if(SPHINX_PATH AND NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + if(SPHINX_PATH AND MATPLOTLIB_FOUND AND NUMPY_FOUND AND NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) set (GUDHI_SPHINX_MESSAGE "Generating API documentation with Sphinx in ${CMAKE_CURRENT_BINARY_DIR}/sphinx/") # User warning - Sphinx is a static pages generator, and configured to work fine with user_version # Images and biblio warnings because not found on developper version @@ -312,5 +388,5 @@ if(CYTHON_FOUND) COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" ${SPHINX_PATH} -b doctest ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/doctest) - endif(SPHINX_PATH AND NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + endif() endif(CYTHON_FOUND) diff --git a/src/cython/cython/cubical_complex.pyx b/src/cython/cython/cubical_complex.pyx index a98a3ec3..e94cd539 100644 --- a/src/cython/cython/cubical_complex.pyx +++ b/src/cython/cython/cubical_complex.pyx @@ -104,22 +104,21 @@ cdef class CubicalComplex: return self.pcohptr != NULL def num_simplices(self): - """This function returns the number of simplices of the simplicial - complex. + """This function returns the number of all cubes in the complex. - :returns: int -- the simplicial complex number of simplices. + :returns: int -- the number of all cubes in the complex. """ return self.thisptr.num_simplices() def dimension(self): - """This function returns the dimension of the simplicial complex. + """This function returns the dimension of the complex. - :returns: int -- the simplicial complex dimension. + :returns: int -- the complex dimension. """ return self.thisptr.dimension() def persistence(self, homology_coeff_field=11, min_persistence=0): - """This function returns the persistence of the simplicial complex. + """This function returns the persistence of the complex. :param homology_coeff_field: The homology coefficient field. Must be a prime number @@ -130,7 +129,7 @@ cdef class CubicalComplex: Sets min_persistence to -1.0 to see all values. :type min_persistence: float. :returns: list of pairs(dimension, pair(birth, death)) -- the - persistence of the simplicial complex. + persistence of the complex. """ if self.pcohptr != NULL: del self.pcohptr @@ -142,12 +141,15 @@ cdef class CubicalComplex: return persistence_result def betti_numbers(self): - """This function returns the Betti numbers of the simplicial complex. + """This function returns the Betti numbers of the complex. :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). :note: betti_numbers function requires persistence function to be launched first. + + :note: betti_numbers function always returns [1, 0, 0, ...] as infinity + filtration cubes are not removed from the complex. """ cdef vector[int] bn_result if self.pcohptr != NULL: @@ -155,8 +157,7 @@ cdef class CubicalComplex: return bn_result def persistent_betti_numbers(self, from_value, to_value): - """This function returns the persistent Betti numbers of the - simplicial complex. + """This function returns the persistent Betti numbers of the complex. :param from_value: The persistence birth limit to be added in the numbers (persistent birth <= from_value). @@ -177,8 +178,8 @@ cdef class CubicalComplex: return pbn_result def persistence_intervals_in_dimension(self, dimension): - """This function returns the persistence intervals of the simplicial - complex in a specific dimension. + """This function returns the persistence intervals of the complex in a + specific dimension. :param dimension: The specific dimension. :type from_value: int. diff --git a/src/cython/cython/nerve_gic.pyx b/src/cython/cython/nerve_gic.pyx new file mode 100644 index 00000000..01dd0a4b --- /dev/null +++ b/src/cython/cython/nerve_gic.pyx @@ -0,0 +1,410 @@ +from cython cimport numeric +from libcpp.vector cimport vector +from libcpp.utility cimport pair +from libcpp.string cimport string +from libcpp cimport bool +import os + +"""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) 2018 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) 2018 Inria" +__license__ = "GPL v3" + +cdef extern from "Nerve_gic_interface.h" namespace "Gudhi": + cdef cppclass Nerve_gic_interface "Gudhi::cover_complex::Nerve_gic_interface": + Nerve_gic_interface() + double compute_confidence_level_from_distance(double distance) + double compute_distance_from_confidence_level(double alpha) + void compute_distribution(int N) + double compute_p_value() + vector[pair[double, double]] compute_PD() + void find_simplices() + void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree) + bool read_point_cloud(string off_file_name) + double set_automatic_resolution() + void set_color_from_coordinate(int k) + void set_color_from_file(string color_file_name) + void set_color_from_range(vector[double] color) + void set_cover_from_file(string cover_file_name) + void set_cover_from_function() + void set_cover_from_Euclidean_Voronoi(int m) + void set_function_from_coordinate(int k) + void set_function_from_file(string func_file_name) + void set_function_from_range(vector[double] function) + void set_gain(double g) + double set_graph_from_automatic_euclidean_rips(int N) + void set_graph_from_file(string graph_file_name) + void set_graph_from_OFF() + void set_graph_from_euclidean_rips(double threshold) + void set_mask(int nodemask) + void set_resolution_with_interval_length(double resolution) + void set_resolution_with_interval_number(int resolution) + void set_subsampling(double constant, double power) + void set_type(string type) + void set_verbose(bool verbose) + vector[int] subpopulation(int c) + void write_info() + void plot_DOT() + void plot_OFF() + void set_point_cloud_from_range(vector[vector[double]] cloud) + +# CoverComplex python interface +cdef class CoverComplex: + """Cover complex data structure. + + The data structure is a simplicial complex, representing a Graph Induced + simplicial Complex (GIC) or a Nerve, and whose simplices are computed with + a cover C of a point cloud P, which often comes from the preimages of + intervals covering the image of a function f defined on P. These intervals + are parameterized by their resolution (either their length or their number) + and their gain (percentage of overlap). To compute a GIC, one also needs a + graph G built on top of P, whose cliques with vertices belonging to + different elements of C correspond to the simplices of the GIC. + """ + + cdef Nerve_gic_interface * thisptr + + # Fake constructor that does nothing but documenting the constructor + def __init__(self): + """CoverComplex constructor. + """ + + # The real cython constructor + def __cinit__(self): + self.thisptr = new Nerve_gic_interface() + + def __dealloc__(self): + if self.thisptr != NULL: + del self.thisptr + + def __is_defined(self): + """Returns true if CoverComplex pointer is not NULL. + """ + return self.thisptr != NULL + + def set_point_cloud_from_range(self, cloud): + """ Reads and stores the input point cloud from a vector stored in memory. + + :param cloud: Input vector containing the point cloud. + :type cloud: vector[vector[double]] + """ + return self.thisptr.set_point_cloud_from_range(cloud) + + def compute_confidence_level_from_distance(self, distance): + """Computes the confidence level of a specific bottleneck distance + threshold. + + :param distance: Bottleneck distance. + :type distance: double + :rtype: double + :returns: Confidence level. + """ + return self.thisptr.compute_confidence_level_from_distance(distance) + + def compute_distance_from_confidence_level(self, alpha): + """Computes the bottleneck distance threshold corresponding to a + specific confidence level. + + :param alpha: Confidence level. + :type alpha: double + :rtype: double + :returns: Bottleneck distance. + """ + return self.thisptr.compute_distance_from_confidence_level(alpha) + + def compute_distribution(self, N=100): + """Computes bootstrapped distances distribution. + + :param N: Loop number (default value is 100). + :type alpha: int + """ + self.thisptr.compute_distribution(N) + + def compute_p_value(self): + """Computes the p-value, i.e. the opposite of the confidence level of + the largest bottleneck distance preserving the points in the + persistence diagram of the output simplicial complex. + + :rtype: double + :returns: p-value. + """ + return self.thisptr.compute_p_value() + + def compute_PD(self): + """Computes the extended persistence diagram of the complex. + """ + return self.thisptr.compute_PD() + + def create_simplex_tree(self): + """ + :returns: A simplex tree created from the Cover complex. + :rtype: SimplexTree + """ + simplex_tree = SimplexTree() + self.thisptr.create_simplex_tree(simplex_tree.thisptr) + return simplex_tree + + def find_simplices(self): + """Computes the simplices of the simplicial complex. + """ + self.thisptr.find_simplices() + + def read_point_cloud(self, off_file): + """Reads and stores the input point cloud from .(n)OFF file. + + :param off_file: Name of the input .OFF or .nOFF file. + :type off_file: string + :rtype: bool + :returns: Read file status. + """ + if os.path.isfile(off_file): + return self.thisptr.read_point_cloud(str.encode(off_file)) + else: + print("file " + off_file + " not found.") + return False + + def set_automatic_resolution(self): + """Computes the optimal length of intervals (i.e. the smallest interval + length avoiding discretization artifacts—see :cite:`Carriere17c`) for a + functional cover. + + :rtype: double + :returns: reso interval length used to compute the cover. + """ + return self.thisptr.set_automatic_resolution() + + def set_color_from_coordinate(self, k=0): + """Computes the function used to color the nodes of the simplicial + complex from the k-th coordinate. + + :param k: Coordinate to use (start at 0). Default value is 0. + :type k: int + """ + return self.thisptr.set_color_from_coordinate(k) + + def set_color_from_file(self, color_file_name): + """Computes the function used to color the nodes of the simplicial + complex from a file containing the function values. + + :param color_file_name: Name of the input color file. + :type color_file_name: string + """ + if os.path.isfile(color_file_name): + self.thisptr.set_color_from_file(str.encode(color_file_name)) + else: + print("file " + color_file_name + " not found.") + + def set_color_from_range(self, color): + """Computes the function used to color the nodes of the simplicial + complex from a vector stored in memory. + + :param color: Input vector of values. + :type color: vector[double] + """ + self.thisptr.set_color_from_range(color) + + def set_cover_from_file(self, cover_file_name): + """Creates the cover C from a file containing the cover elements of + each point (the order has to be the same as in the input file!). + + :param cover_file_name: Name of the input cover file. + :type cover_file_name: string + """ + if os.path.isfile(cover_file_name): + self.thisptr.set_cover_from_file(str.encode(cover_file_name)) + else: + print("file " + cover_file_name + " not found.") + + def set_cover_from_function(self): + """Creates a cover C from the preimages of the function f. + """ + self.thisptr.set_cover_from_function() + + def set_cover_from_Voronoi(self, m=100): + """Creates the cover C from the Voronoï cells of a subsampling of the + point cloud. + + :param m: Number of points in the subsample. Default value is 100. + :type m: int + """ + self.thisptr.set_cover_from_Euclidean_Voronoi(m) + + def set_function_from_coordinate(self, k): + """Creates the function f from the k-th coordinate of the point cloud. + + :param k: Coordinate to use (start at 0). + :type k: int + """ + self.thisptr.set_function_from_coordinate(k) + + def set_function_from_file(self, func_file_name): + """Creates the function f from a file containing the function values. + + :param func_file_name: Name of the input function file. + :type func_file_name: string + """ + if os.path.isfile(func_file_name): + self.thisptr.set_function_from_file(str.encode(func_file_name)) + else: + print("file " + func_file_name + " not found.") + + def set_function_from_range(self, function): + """Creates the function f from a vector stored in memory. + + :param function: Input vector of values. + :type function: vector[double] + """ + self.thisptr.set_function_from_range(function) + + def set_gain(self, g = 0.3): + """Sets a gain from a value stored in memory. + + :param g: Gain (default value is 0.3). + :type g: double + """ + self.thisptr.set_gain(g) + + def set_graph_from_automatic_rips(self, N=100): + """Creates a graph G from a Rips complex whose threshold value is + automatically tuned with subsampling—see. + + :param N: Number of subsampling iteration (the default reasonable value + is 100, but there is no guarantee on how to choose it). + :type N: int + :rtype: double + :returns: Delta threshold used for computing the Rips complex. + """ + return self.thisptr.set_graph_from_automatic_euclidean_rips(N) + + def set_graph_from_file(self, graph_file_name): + """Creates a graph G from a file containing the edges. + + :param graph_file_name: Name of the input graph file. The graph file + contains one edge per line, each edge being represented by the IDs of + its two nodes. + :type graph_file_name: string + """ + if os.path.isfile(graph_file_name): + self.thisptr.set_graph_from_file(str.encode(graph_file_name)) + else: + print("file " + graph_file_name + " not found.") + + def set_graph_from_OFF(self): + """Creates a graph G from the triangulation given by the input OFF + file. + """ + self.thisptr.set_graph_from_OFF() + + def set_graph_from_rips(self, threshold): + """Creates a graph G from a Rips complex. + + :param threshold: Threshold value for the Rips complex. + :type threshold: double + """ + self.thisptr.set_graph_from_euclidean_rips(threshold) + + def set_mask(self, nodemask): + """Sets the mask, which is a threshold integer such that nodes in the + complex that contain a number of data points which is less than or + equal to this threshold are not displayed. + + :param nodemask: Threshold. + :type nodemask: int + """ + self.thisptr.set_mask(nodemask) + + def set_resolution_with_interval_length(self, resolution): + """Sets a length of intervals from a value stored in memory. + + :param resolution: Length of intervals. + :type resolution: double + """ + self.thisptr.set_resolution_with_interval_length(resolution) + + def set_resolution_with_interval_number(self, resolution): + """Sets a number of intervals from a value stored in memory. + + :param resolution: Number of intervals. + :type resolution: int + """ + self.thisptr.set_resolution_with_interval_number(resolution) + + def set_subsampling(self, constant, power): + """Sets the constants used to subsample the data set. These constants + are explained in :cite:`Carriere17c`. + + :param constant: Constant. + :type constant: double + :param power: Power. + :type resolution: double + """ + self.thisptr.set_subsampling(constant, power) + + def set_type(self, type): + """Specifies whether the type of the output simplicial complex. + + :param type: either "GIC" or "Nerve". + :type type: string + """ + self.thisptr.set_type(str.encode(type)) + + def set_verbose(self, verbose): + """Specifies whether the program should display information or not. + + :param verbose: true = display info, false = do not display info. + :type verbose: boolean + """ + self.thisptr.set_verbose(verbose) + + def subpopulation(self, c): + """Returns the data subset corresponding to a specific node of the + created complex. + + :param c: ID of the node. + :type c: int + :rtype: vector[int] + :returns: Vector of IDs of data points. + """ + return self.thisptr.subpopulation(c) + + def write_info(self): + """Creates a .txt file called SC.txt describing the 1-skeleton, which can + then be plotted with e.g. KeplerMapper. + """ + return self.thisptr.write_info() + + def plot_dot(self): + """Creates a .dot file called SC.dot for neato (part of the graphviz + package) once the simplicial complex is computed to get a visualization of + its 1-skeleton in a .pdf file. + """ + return self.thisptr.plot_DOT() + + def plot_off(self): + """Creates a .off file called SC.off for 3D visualization, which contains + the 2-skeleton of the GIC. This function assumes that the cover has been + computed with Voronoi. If data points are in 1D or 2D, the remaining + coordinates of the points embedded in 3D are set to 0. + """ + return self.thisptr.plot_OFF() diff --git a/src/cython/cython/periodic_cubical_complex.pyx b/src/cython/cython/periodic_cubical_complex.pyx index c25b83e9..e626950b 100644 --- a/src/cython/cython/periodic_cubical_complex.pyx +++ b/src/cython/cython/periodic_cubical_complex.pyx @@ -106,22 +106,21 @@ cdef class PeriodicCubicalComplex: return self.pcohptr != NULL def num_simplices(self): - """This function returns the number of simplices of the simplicial - complex. + """This function returns the number of all cubes in the complex. - :returns: int -- the simplicial complex number of simplices. + :returns: int -- the number of all cubes in the complex. """ return self.thisptr.num_simplices() def dimension(self): - """This function returns the dimension of the simplicial complex. + """This function returns the dimension of the complex. - :returns: int -- the simplicial complex dimension. + :returns: int -- the complex dimension. """ return self.thisptr.dimension() def persistence(self, homology_coeff_field=11, min_persistence=0): - """This function returns the persistence of the simplicial complex. + """This function returns the persistence of the complex. :param homology_coeff_field: The homology coefficient field. Must be a prime number @@ -132,7 +131,7 @@ cdef class PeriodicCubicalComplex: Sets min_persistence to -1.0 to see all values. :type min_persistence: float. :returns: list of pairs(dimension, pair(birth, death)) -- the - persistence of the simplicial complex. + persistence of the complex. """ if self.pcohptr != NULL: del self.pcohptr @@ -144,12 +143,15 @@ cdef class PeriodicCubicalComplex: return persistence_result def betti_numbers(self): - """This function returns the Betti numbers of the simplicial complex. + """This function returns the Betti numbers of the complex. :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). :note: betti_numbers function requires persistence function to be launched first. + + :note: betti_numbers function always returns [1, 0, 0, ...] as infinity + filtration cubes are not removed from the complex. """ cdef vector[int] bn_result if self.pcohptr != NULL: @@ -157,8 +159,7 @@ cdef class PeriodicCubicalComplex: return bn_result def persistent_betti_numbers(self, from_value, to_value): - """This function returns the persistent Betti numbers of the - simplicial complex. + """This function returns the persistent Betti numbers of the complex. :param from_value: The persistence birth limit to be added in the numbers (persistent birth <= from_value). @@ -179,8 +180,8 @@ cdef class PeriodicCubicalComplex: return pbn_result def persistence_intervals_in_dimension(self, dimension): - """This function returns the persistence intervals of the simplicial - complex in a specific dimension. + """This function returns the persistence intervals of the complex in a + specific dimension. :param dimension: The specific dimension. :type from_value: int. diff --git a/src/cython/cython/persistence_graphical_tools.py b/src/cython/cython/persistence_graphical_tools.py index e2405e96..314bd6db 100755 --- a/src/cython/cython/persistence_graphical_tools.py +++ b/src/cython/cython/persistence_graphical_tools.py @@ -1,7 +1,3 @@ -import matplotlib.pyplot as plt -import numpy as np -import os - """This file is part of the Gudhi Library. The Gudhi library (Geometric Understanding in Higher Dimensions) is a generic C++ library for computational topology. @@ -28,175 +24,197 @@ __author__ = "Vincent Rouvreau, Bertrand Michel" __copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" -def __min_birth_max_death(persistence, band_boot=0.): - """This function returns (min_birth, max_death) from the persistence. - - :param persistence: The persistence to plot. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param band_boot: bootstrap band - :type band_boot: float. - :returns: (float, float) -- (min_birth, max_death). - """ - # Look for minimum birth date and maximum death date for plot optimisation - max_death = 0 - min_birth = persistence[0][1][0] - for interval in reversed(persistence): - if float(interval[1][1]) != float('inf'): - if float(interval[1][1]) > max_death: - max_death = float(interval[1][1]) - if float(interval[1][0]) > max_death: - max_death = float(interval[1][0]) - if float(interval[1][0]) < min_birth: - min_birth = float(interval[1][0]) - if band_boot > 0.: - max_death += band_boot - return (min_birth, max_death) +try: + import matplotlib.pyplot as plt + import matplotlib.patches as mpatches + import numpy as np + import os + + def __min_birth_max_death(persistence, band=0.): + """This function returns (min_birth, max_death) from the persistence. + + :param persistence: The persistence to plot. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param band: band + :type band: float. + :returns: (float, float) -- (min_birth, max_death). + """ + # Look for minimum birth date and maximum death date for plot optimisation + max_death = 0 + min_birth = persistence[0][1][0] + for interval in reversed(persistence): + if float(interval[1][1]) != float('inf'): + if float(interval[1][1]) > max_death: + max_death = float(interval[1][1]) + if float(interval[1][0]) > max_death: + max_death = float(interval[1][0]) + if float(interval[1][0]) < min_birth: + min_birth = float(interval[1][0]) + if band > 0.: + max_death += band + return (min_birth, max_death) -""" -Only 13 colors for the palette -""" -palette = ['#ff0000', '#00ff00', '#0000ff', '#00ffff', '#ff00ff', '#ffff00', - '#000000', '#880000', '#008800', '#000088', '#888800', '#880088', - '#008888'] - -def show_palette_values(alpha=0.6): - """This function shows palette color values in function of the dimension. - - :param alpha: alpha value in [0.0, 1.0] for horizontal bars (default is 0.6). - :type alpha: float. - :returns: plot the dimension palette values. - """ - colors = [] - for color in palette: - colors.append(color) - - y_pos = np.arange(len(palette)) - - plt.barh(y_pos, y_pos + 1, align='center', alpha=alpha, color=colors) - plt.ylabel('Dimension') - plt.title('Dimension palette values') - return plt - -def plot_persistence_barcode(persistence=[], persistence_file='', alpha=0.6, max_barcodes=0): - """This function plots the persistence bar code. - - :param persistence: The persistence to plot. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A persistence file style name (reset persistence if both are set). - :type persistence_file: string - :param alpha: alpha value in [0.0, 1.0] for horizontal bars (default is 0.6). - :type alpha: float. - :param max_barcodes: number of maximal barcodes to be displayed - (persistence will be sorted by life time if max_barcodes is set) - :type max_barcodes: int. - :returns: plot -- An horizontal bar plot of persistence. """ - if persistence_file is not '': - if os.path.isfile(persistence_file): - # Reset persistence - persistence = [] - diag = read_persistence_intervals_grouped_by_dimension(persistence_file=persistence_file) - for key in diag.keys(): - for persistence_interval in diag[key]: - persistence.append((key, persistence_interval)) - else: - print("file " + persistence_file + " not found.") - return None - - if max_barcodes > 0 and max_barcodes < len(persistence): - # Sort by life time, then takes only the max_plots elements - persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_barcodes] - - (min_birth, max_death) = __min_birth_max_death(persistence) - ind = 0 - delta = ((max_death - min_birth) / 10.0) - # Replace infinity values with max_death + delta for bar code to be more - # readable - infinity = max_death + delta - axis_start = min_birth - delta - # Draw horizontal bars in loop - for interval in reversed(persistence): - if float(interval[1][1]) != float('inf'): - # Finite death case - plt.barh(ind, (interval[1][1] - interval[1][0]), height=0.8, - left = interval[1][0], alpha=alpha, - color = palette[interval[0]]) - else: - # Infinite death case for diagram to be nicer - plt.barh(ind, (infinity - interval[1][0]), height=0.8, - left = interval[1][0], alpha=alpha, - color = palette[interval[0]]) - ind = ind + 1 - - plt.title('Persistence barcode') - # Ends plot on infinity value and starts a little bit before min_birth - plt.axis([axis_start, infinity, 0, ind]) - return plt - -def plot_persistence_diagram(persistence=[], persistence_file='', alpha=0.6, band_boot=0., max_plots=0): - """This function plots the persistence diagram with an optional confidence band. - - :param persistence: The persistence to plot. - :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A persistence file style name (reset persistence if both are set). - :type persistence_file: string - :param alpha: alpha value in [0.0, 1.0] for points and horizontal infinity line (default is 0.6). - :type alpha: float. - :param band_boot: bootstrap band (not displayed if :math:`\leq` 0.) - :type band_boot: float. - :param max_plots: number of maximal plots to be displayed - :type max_plots: int. - :returns: plot -- A diagram plot of persistence. + Only 13 colors for the palette """ - if persistence_file is not '': - if os.path.isfile(persistence_file): - # Reset persistence - persistence = [] - diag = read_persistence_intervals_grouped_by_dimension(persistence_file=persistence_file) - for key in diag.keys(): - for persistence_interval in diag[key]: - persistence.append((key, persistence_interval)) - else: - print("file " + persistence_file + " not found.") - return None - - if max_plots > 0 and max_plots < len(persistence): - # Sort by life time, then takes only the max_plots elements - persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_plots] - - (min_birth, max_death) = __min_birth_max_death(persistence, band_boot) - ind = 0 - delta = ((max_death - min_birth) / 10.0) - # Replace infinity values with max_death + delta for diagram to be more - # readable - infinity = max_death + delta - axis_start = min_birth - delta - - # line display of equation : birth = death - x = np.linspace(axis_start, infinity, 1000) - # infinity line and text - plt.plot(x, x, color='k', linewidth=1.0) - plt.plot(x, [infinity] * len(x), linewidth=1.0, color='k', alpha=alpha) - plt.text(axis_start, infinity, r'$\infty$', color='k', alpha=alpha) - # bootstrap band - if band_boot > 0.: - plt.fill_between(x, x, x+band_boot, alpha=alpha, facecolor='red') - - # Draw points in loop - for interval in reversed(persistence): - if float(interval[1][1]) != float('inf'): - # Finite death case - plt.scatter(interval[1][0], interval[1][1], alpha=alpha, - color = palette[interval[0]]) - else: - # Infinite death case for diagram to be nicer - plt.scatter(interval[1][0], infinity, alpha=alpha, - color = palette[interval[0]]) - ind = ind + 1 - - plt.title('Persistence diagram') - plt.xlabel('Birth') - plt.ylabel('Death') - # Ends plot on infinity value and starts a little bit before min_birth - plt.axis([axis_start, infinity, axis_start, infinity + delta]) - return plt + palette = ['#ff0000', '#00ff00', '#0000ff', '#00ffff', '#ff00ff', '#ffff00', + '#000000', '#880000', '#008800', '#000088', '#888800', '#880088', + '#008888'] + + def plot_persistence_barcode(persistence=[], persistence_file='', alpha=0.6, + max_barcodes=1000, inf_delta=0.1, legend=False): + """This function plots the persistence bar code from persistence values list + or from a :doc:`persistence file <fileformats>`. + + :param persistence: Persistence values list. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param persistence_file: A :doc:`persistence file <fileformats>` style name + (reset persistence if both are set). + :type persistence_file: string + :param alpha: barcode transparency value (0.0 transparent through 1.0 opaque - default is 0.6). + :type alpha: float. + :param max_barcodes: number of maximal barcodes to be displayed. + Set it to 0 to see all, Default value is 1000. + (persistence will be sorted by life time if max_barcodes is set) + :type max_barcodes: int. + :param inf_delta: Infinity is placed at ((max_death - min_birth) x inf_delta). + A reasonable value is between 0.05 and 0.5 - default is 0.1. + :type inf_delta: float. + :returns: A matplotlib object containing horizontal bar plot of persistence + (launch `show()` method on it to display it). + """ + if persistence_file is not '': + if os.path.isfile(persistence_file): + # Reset persistence + persistence = [] + diag = read_persistence_intervals_grouped_by_dimension(persistence_file=persistence_file) + for key in diag.keys(): + for persistence_interval in diag[key]: + persistence.append((key, persistence_interval)) + else: + print("file " + persistence_file + " not found.") + return None + + if max_barcodes > 0 and max_barcodes < len(persistence): + # Sort by life time, then takes only the max_plots elements + persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_barcodes] + + persistence = sorted(persistence, key=lambda birth: birth[1][0]) + + (min_birth, max_death) = __min_birth_max_death(persistence) + ind = 0 + delta = ((max_death - min_birth) * inf_delta) + # Replace infinity values with max_death + delta for bar code to be more + # readable + infinity = max_death + delta + axis_start = min_birth - delta + # Draw horizontal bars in loop + for interval in reversed(persistence): + if float(interval[1][1]) != float('inf'): + # Finite death case + plt.barh(ind, (interval[1][1] - interval[1][0]), height=0.8, + left = interval[1][0], alpha=alpha, + color = palette[interval[0]], + linewidth=0) + else: + # Infinite death case for diagram to be nicer + plt.barh(ind, (infinity - interval[1][0]), height=0.8, + left = interval[1][0], alpha=alpha, + color = palette[interval[0]], + linewidth=0) + ind = ind + 1 + + if legend: + dimensions = list(set(item[0] for item in persistence)) + plt.legend(handles=[mpatches.Patch(color=palette[dim], + label=str(dim)) for dim in dimensions], + loc='lower right') + plt.title('Persistence barcode') + # Ends plot on infinity value and starts a little bit before min_birth + plt.axis([axis_start, infinity, 0, ind]) + return plt + + def plot_persistence_diagram(persistence=[], persistence_file='', alpha=0.6, + band=0., max_plots=1000, inf_delta=0.1, legend=False): + """This function plots the persistence diagram from persistence values list + or from a :doc:`persistence file <fileformats>`. + + :param persistence: Persistence values list. + :type persistence: list of tuples(dimension, tuple(birth, death)). + :param persistence_file: A :doc:`persistence file <fileformats>` style name + (reset persistence if both are set). + :type persistence_file: string + :param alpha: plot transparency value (0.0 transparent through 1.0 opaque - default is 0.6). + :type alpha: float. + :param band: band (not displayed if :math:`\leq` 0. - default is 0.) + :type band: float. + :param max_plots: number of maximal plots to be displayed + Set it to 0 to see all, Default value is 1000. + (persistence will be sorted by life time if max_plots is set) + :type max_plots: int. + :param inf_delta: Infinity is placed at ((max_death - min_birth) x inf_delta). + A reasonable value is between 0.05 and 0.5 - default is 0.1. + :type inf_delta: float. + :returns: A matplotlib object containing diagram plot of persistence + (launch `show()` method on it to display it). + """ + if persistence_file is not '': + if os.path.isfile(persistence_file): + # Reset persistence + persistence = [] + diag = read_persistence_intervals_grouped_by_dimension(persistence_file=persistence_file) + for key in diag.keys(): + for persistence_interval in diag[key]: + persistence.append((key, persistence_interval)) + else: + print("file " + persistence_file + " not found.") + return None + + if max_plots > 0 and max_plots < len(persistence): + # Sort by life time, then takes only the max_plots elements + persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_plots] + + (min_birth, max_death) = __min_birth_max_death(persistence, band) + ind = 0 + delta = ((max_death - min_birth) * inf_delta) + # Replace infinity values with max_death + delta for diagram to be more + # readable + infinity = max_death + delta + axis_start = min_birth - delta + + # line display of equation : birth = death + x = np.linspace(axis_start, infinity, 1000) + # infinity line and text + plt.plot(x, x, color='k', linewidth=1.0) + plt.plot(x, [infinity] * len(x), linewidth=1.0, color='k', alpha=alpha) + plt.text(axis_start, infinity, r'$\infty$', color='k', alpha=alpha) + # bootstrap band + if band > 0.: + plt.fill_between(x, x, x+band, alpha=alpha, facecolor='red') + + # Draw points in loop + for interval in reversed(persistence): + if float(interval[1][1]) != float('inf'): + # Finite death case + plt.scatter(interval[1][0], interval[1][1], alpha=alpha, + color = palette[interval[0]]) + else: + # Infinite death case for diagram to be nicer + plt.scatter(interval[1][0], infinity, alpha=alpha, + color = palette[interval[0]]) + ind = ind + 1 + + if legend: + dimensions = list(set(item[0] for item in persistence)) + plt.legend(handles=[mpatches.Patch(color=palette[dim], label=str(dim)) for dim in dimensions]) + + plt.title('Persistence diagram') + plt.xlabel('Birth') + plt.ylabel('Death') + # Ends plot on infinity value and starts a little bit before min_birth + plt.axis([axis_start, infinity, axis_start, infinity + delta]) + return plt + +except ImportError: + # Continue in case of import error, functions won't be available + pass diff --git a/src/cython/cython/rips_complex.pyx b/src/cython/cython/rips_complex.pyx index 59c16bff..30ca4443 100644 --- a/src/cython/cython/rips_complex.pyx +++ b/src/cython/cython/rips_complex.pyx @@ -51,7 +51,7 @@ cdef class RipsComplex: """RipsComplex constructor. :param max_edge_length: Rips value. - :type max_edge_length: int + :type max_edge_length: float :param points: A list of points in d-Dimension. :type points: list of list of double diff --git a/src/cython/cython/simplex_tree.pyx b/src/cython/cython/simplex_tree.pyx index 8abeb5f8..e302486b 100644 --- a/src/cython/cython/simplex_tree.pyx +++ b/src/cython/cython/simplex_tree.pyx @@ -55,6 +55,7 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": void expansion(int max_dim) void remove_maximal_simplex(vector[int] simplex) bool prune_above_filtration(double filtration) + bool make_filtration_non_decreasing() cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": cdef cppclass Simplex_tree_persistence_interface "Gudhi::Persistent_cohomology_interface<Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_full_featured>>": @@ -64,6 +65,7 @@ cdef extern from "Persistent_cohomology_interface.h" namespace "Gudhi": vector[int] persistent_betti_numbers(double from_value, double to_value) vector[pair[double,double]] intervals_in_dimension(int dimension) void write_output_diagram(string diagram_file_name) + vector[pair[vector[int], vector[int]]] persistence_pairs() # SimplexTree python interface cdef class SimplexTree: @@ -399,6 +401,26 @@ cdef class SimplexTree: """ self.thisptr.expansion(max_dim) + def make_filtration_non_decreasing(self): + """This function ensures that each simplex has a higher filtration + value than its faces by increasing the filtration values. + + :returns: The filtration modification information. + :rtype: bint + + + .. note:: + + Some simplex tree functions require the filtration to be valid. + make_filtration_non_decreasing function is not launching + :func:`initialize_filtration()<gudhi.SimplexTree.initialize_filtration>` + but returns the filtration modification + information. If the complex has changed , please call + :func:`initialize_filtration()<gudhi.SimplexTree.initialize_filtration>` + to recompute it. + """ + return self.thisptr.make_filtration_non_decreasing() + def persistence(self, homology_coeff_field=11, min_persistence=0, persistence_dim_max = False): """This function returns the persistence of the simplicial complex. @@ -486,6 +508,25 @@ cdef class SimplexTree: " to be launched first.") return intervals_result + def persistence_pairs(self): + """This function returns the persistence pairs of the simplicial + complex. + + :returns: The persistence intervals. + :rtype: list of pair of list of int + + :note: intervals_in_dim function requires + :func:`persistence()<gudhi.SimplexTree.persistence>` + function to be launched first. + """ + cdef vector[pair[vector[int],vector[int]]] persistence_pairs_result + if self.pcohptr != NULL: + persistence_pairs_result = self.pcohptr.persistence_pairs() + else: + print("persistence_pairs function requires persistence function" + " to be launched first.") + return persistence_pairs_result + def write_persistence_diagram(self, persistence_file=''): """This function writes the persistence intervals of the simplicial complex in a user given file name. diff --git a/src/cython/cython/subsampling.pyx b/src/cython/cython/subsampling.pyx index ac09b7a3..e9d61a37 100644 --- a/src/cython/cython/subsampling.pyx +++ b/src/cython/cython/subsampling.pyx @@ -112,7 +112,8 @@ def pick_n_random_points(points=None, off_file='', nb_points=0): return subsampling_n_random_points(points, nb_points) def sparsify_point_set(points=None, off_file='', min_squared_dist=0.0): - """Subsample a point set by picking random vertices. + """Outputs a subset of the input points so that the squared distance + between any two points is greater than or equal to min_squared_dist. :param points: The input point set. :type points: vector[vector[double]]. @@ -122,8 +123,9 @@ def sparsify_point_set(points=None, off_file='', min_squared_dist=0.0): :param off_file: An OFF file style name. :type off_file: string - :param min_squared_dist: Number of points of the subsample. - :type min_squared_dist: unsigned. + :param min_squared_dist: Minimum squared distance separating the output \ + points. + :type min_squared_dist: float. :returns: The subsample point set. :rtype: vector[vector[double]] """ diff --git a/src/cython/cython/tangential_complex.pyx b/src/cython/cython/tangential_complex.pyx index 10fa1468..4bb07076 100644 --- a/src/cython/cython/tangential_complex.pyx +++ b/src/cython/cython/tangential_complex.pyx @@ -33,9 +33,9 @@ __license__ = "GPL v3" cdef extern from "Tangential_complex_interface.h" namespace "Gudhi": cdef cppclass Tangential_complex_interface "Gudhi::tangential_complex::Tangential_complex_interface": - Tangential_complex_interface(vector[vector[double]] points) + Tangential_complex_interface(int intrisic_dim, vector[vector[double]] points) # bool from_file is a workaround for cython to find the correct signature - Tangential_complex_interface(string off_file, bool from_file) + Tangential_complex_interface(int intrisic_dim, string off_file, bool from_file) vector[double] get_point(unsigned vertex) unsigned number_of_vertices() unsigned number_of_simplices() @@ -54,9 +54,12 @@ cdef class TangentialComplex: cdef Tangential_complex_interface * thisptr # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, off_file=''): + def __init__(self, intrisic_dim, points=None, off_file=''): """TangentialComplex constructor. + :param intrisic_dim: Intrinsic dimension of the manifold. + :type intrisic_dim: integer + :param points: A list of points in d-Dimension. :type points: list of list of double @@ -67,17 +70,17 @@ cdef class TangentialComplex: """ # The real cython constructor - def __cinit__(self, points=None, off_file=''): + def __cinit__(self, intrisic_dim, points=None, off_file=''): if off_file is not '': if os.path.isfile(off_file): - self.thisptr = new Tangential_complex_interface(str.encode(off_file), True) + self.thisptr = new Tangential_complex_interface(intrisic_dim, str.encode(off_file), True) else: print("file " + off_file + " not found.") else: if points is None: # Empty tangential construction points=[] - self.thisptr = new Tangential_complex_interface(points) + self.thisptr = new Tangential_complex_interface(intrisic_dim, points) def __dealloc__(self): diff --git a/src/cython/doc/_templates/layout.html b/src/cython/doc/_templates/layout.html index c9356116..bc0e9658 100644 --- a/src/cython/doc/_templates/layout.html +++ b/src/cython/doc/_templates/layout.html @@ -56,6 +56,12 @@ </a></p> {%- endif %} {%- endblock %} + <h2><a href="index.html">GUDHI</a></h2> + <h2><a href="fileformats.html">File formats</a></h2> + <h2><a href="installation.html">GUDHI installation</a></h2> + <h2><a href="citation.html">Acknowledging the GUDHI library</a></h2> + <h2><a href="genindex.html">Index</a></h2> + <h2><a href="examples.html">Examples</a></h2> {%- if sidebars != None %} {#- new style sidebar: explicitly include/exclude templates #} {%- for sidebartemplate in sidebars %} @@ -64,13 +70,6 @@ {%- else %} {#- old style sidebars: using blocks -- should be deprecated #} {%- block sidebartoc %} -<h2><a href="index.html">GUDHI</a></h2> -<h2><a href="fileformats.html">File formats</a></h2> -<h2><a href="installation.html">GUDHI installation</a></h2> -<h2><a href="citation.html">Acknowledging the GUDHI library</a></h2> -<h2><a href="genindex.html">Index</a></h2> -<h2><a href="examples.html">Examples</a></h2> - {%- include "localtoc.html" %} {%- endblock %} {%- block sidebarrel %} @@ -108,7 +107,7 @@ {%- macro css() %} <!-- GUDHI website css for header BEGIN --> -<link rel="stylesheet" type="text/css" href="http://gudhi.gforge.inria.fr/assets/css/styles_feeling_responsive.css" /> +<link rel="stylesheet" type="text/css" href="https://gudhi.inria.fr/assets/css/styles_feeling_responsive.css" /> <!-- GUDHI website css for header END --> <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" /> <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" /> @@ -166,60 +165,61 @@ <body role="document"> <!-- GUDHI website header BEGIN --> <div id="navigation" class="sticky"> - <nav class="top-bar" role="navigation" data-topbar> - <ul class="title-area"> - <li class="name"> - <h1 class="show-for-small-only"><a href="http://gudhi.gforge.inria.fr" class="icon-tree"> GUDHI C++ library</a></h1> - </li> - <!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone --> - <li class="toggle-topbar menu-icon"><a href="#"><span>Navigation</span></a></li> - </ul> - <section class="top-bar-section"> - <ul class="right"> - <li class="divider"></li> - <li><a href="http://gudhi.gforge.inria.fr/contact/">Contact</a></li> - </ul> - <ul class="left"> - <li><a href="http://gudhi.gforge.inria.fr/"> <img src="http://gudhi.gforge.inria.fr/assets/img/home.png" alt=" GUDHI"> GUDHI </a></li> - <li class="divider"></li> - <li class="has-dropdown"> - <a href="#">Project</a> - <ul class="dropdown"> - <li><a href="http://gudhi.gforge.inria.fr/people/">People</a></li> - <li><a href="http://gudhi.gforge.inria.fr/keepintouch/">Keep in touch</a></li> - <li><a href="http://gudhi.gforge.inria.fr/partners/">Partners and Funding</a></li> - <li><a href="http://gudhi.gforge.inria.fr/relatedprojects/">Related projects</a></li> - <li><a href="http://gudhi.gforge.inria.fr/theyaretalkingaboutus/">They are talking about us</a></li> - </ul> - </li> - <li class="divider"></li> - <li class="has-dropdown"> - <a href="#">Download</a> - <ul class="dropdown"> - <li><a href="http://gudhi.gforge.inria.fr/licensing/">Licensing</a></li> - <li><a href="https://gforge.inria.fr/frs/?group_id=3865" target="_blank">Get the sources</a></li> - <li><a href="https://gforge.inria.fr/frs/download.php/file/37365/2018-02-01-16-59-31_GUDHI_2.1.0_OSX_UTILS.tar.gz" target="_blank">Utils for Mac OSx</a></li> - <li><a href="https://gforge.inria.fr/frs/download.php/file/37366/2018-01-31-09-25-53_GUDHI_2.1.0_WIN64_UTILS.zip" target="_blank">Utils for Win x64</a></li> - </ul> - </li> - <li class="divider"></li> - <li class="has-dropdown"> - <a href="#">Documentation</a> - <ul class="dropdown"> - <li><a href="http://gudhi.gforge.inria.fr/doc/latest/">C++ documentation</a></li> - <li><a href="http://gudhi.gforge.inria.fr/doc/latest/installation.html">C++ installation manual</a></li> - <li><a href="http://gudhi.gforge.inria.fr/python/latest/">Python documentation</a></li> - <li><a href="http://gudhi.gforge.inria.fr/python/latest/installation.html">Python installation manual</a></li> - <li><a href="http://gudhi.gforge.inria.fr/utils/">Utilities</a></li> - <li><a href="http://bertrand.michel.perso.math.cnrs.fr/Enseignements/TDA-Gudhi-Python.html" target="_blank">Tutorial</a></li> - </ul> - </li> - <li class="divider"></li> - <li><a href="http://gudhi.gforge.inria.fr/interfaces/">Interfaces</a></li> - <li class="divider"></li> - </ul> - </section> - </nav> + <nav class="top-bar" role="navigation" data-topbar> + <ul class="title-area"> + <li class="name"> + <h1 class="show-for-small-only"><a href="" class="icon-tree"> GUDHI C++ library</a></h1> + </li> + <!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone --> + <li class="toggle-topbar menu-icon"><a href="#"><span>Navigation</span></a></li> + </ul> + <section class="top-bar-section"> + <ul class="right"> + <li class="divider"></li> + <li><a href="/contact/">Contact</a></li> + </ul> + <ul class="left"> + <li><a href="/"> <img src="/assets/img/home.png" alt=" GUDHI"> GUDHI </a></li> + <li class="divider"></li> + <li class="has-dropdown"> + <a href="#">Project</a> + <ul class="dropdown"> + <li><a href="/people/">People</a></li> + <li><a href="/keepintouch/">Keep in touch</a></li> + <li><a href="/partners/">Partners and Funding</a></li> + <li><a href="/relatedprojects/">Related projects</a></li> + <li><a href="/theyaretalkingaboutus/">They are talking about us</a></li> + </ul> + </li> + <li class="divider"></li> + <li class="has-dropdown"> + <a href="#">Download</a> + <ul class="dropdown"> + <li><a href="/licensing/">Licensing</a></li> + <li><a href="https://gforge.inria.fr/frs/download.php/latestzip/5253/library-latest.zip" target="_blank">Get the latest sources</a></li> + <li><a href="https://gforge.inria.fr/frs/download.php/latestzip/5280/utils_osx-latest.zip" target="_blank">Utils for Mac OSx</a></li> + <li><a href="https://gforge.inria.fr/frs/download.php/latestzip/5279/utils_win64-latest.zip" target="_blank">Utils for Win x64</a></li> + </ul> + </li> + <li class="divider"></li> + <li class="has-dropdown"> + <a href="#">Documentation</a> + <ul class="dropdown"> + <li><a href="/doc/latest/">C++ documentation</a></li> + <li><a href="/doc/latest/installation.html">C++ installation manual</a></li> + <li><a href="/python/latest/">Python documentation</a></li> + <li><a href="/python/latest/installation.html">Python installation manual</a></li> + <li><a href="/utils/">Utilities</a></li> + <li><a href="/tutorials/">Tutorials</a></li> + <li><a href="/dockerfile/">Dockerfile</a></li> + </ul> + </li> + <li class="divider"></li> + <li><a href="/interfaces/">Interfaces</a></li> + <li class="divider"></li> + </ul> + </section> + </nav> </div><!-- /#navigation --> <!-- GUDHI website header BEGIN --> diff --git a/src/cython/doc/alpha_complex_ref.rst b/src/cython/doc/alpha_complex_ref.rst index 6a122b09..7da79543 100644 --- a/src/cython/doc/alpha_complex_ref.rst +++ b/src/cython/doc/alpha_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ============================== Alpha complex reference manual ============================== diff --git a/src/cython/doc/alpha_complex_sum.rst b/src/cython/doc/alpha_complex_sum.inc index 1680a712..1680a712 100644 --- a/src/cython/doc/alpha_complex_sum.rst +++ b/src/cython/doc/alpha_complex_sum.inc diff --git a/src/cython/doc/alpha_complex_user.rst b/src/cython/doc/alpha_complex_user.rst index db7edd6f..d1e9c7cd 100644 --- a/src/cython/doc/alpha_complex_user.rst +++ b/src/cython/doc/alpha_complex_user.rst @@ -1,11 +1,15 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Alpha complex user manual ========================= Definition ---------- -.. include:: alpha_complex_sum.rst +.. include:: alpha_complex_sum.inc -Alpha_complex is constructing a :doc:`Simplex_tree <simplex_tree_sum>` using +Alpha_complex is constructing a :doc:`Simplex_tree <simplex_tree_ref>` using `Delaunay Triangulation <http://doc.cgal.org/latest/Triangulation/index.html#Chapter_Triangulations>`_ :cite:`cgal:hdj-t-15b` from `CGAL <http://www.cgal.org/>`_ (the Computational Geometry Algorithms Library :cite:`cgal:eb-15b`). @@ -99,9 +103,9 @@ Filtration value computation algorithm **end for** **end for** **end for** - + make_filtration_non_decreasing() - + prune_above_filtration() Dimension 2 diff --git a/src/cython/doc/bottleneck_distance_sum.rst b/src/cython/doc/bottleneck_distance_sum.inc index 030fad9e..030fad9e 100644 --- a/src/cython/doc/bottleneck_distance_sum.rst +++ b/src/cython/doc/bottleneck_distance_sum.inc diff --git a/src/cython/doc/bottleneck_distance_user.rst b/src/cython/doc/bottleneck_distance_user.rst index 7692dce2..605db022 100644 --- a/src/cython/doc/bottleneck_distance_user.rst +++ b/src/cython/doc/bottleneck_distance_user.rst @@ -1,9 +1,13 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Bottleneck distance user manual =============================== Definition ---------- -.. include:: bottleneck_distance_sum.rst +.. include:: bottleneck_distance_sum.inc Function -------- diff --git a/src/cython/doc/citation.rst b/src/cython/doc/citation.rst index f4fdf83b..117eb9dd 100644 --- a/src/cython/doc/citation.rst +++ b/src/cython/doc/citation.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Acknowledging the GUDHI library ############################### diff --git a/src/cython/doc/conf.py b/src/cython/doc/conf.py index a13c9751..4a54d4fd 100755 --- a/src/cython/doc/conf.py +++ b/src/cython/doc/conf.py @@ -85,7 +85,7 @@ version = gudhi.__version__ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ['_build', '*.inc'] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -125,6 +125,7 @@ html_theme_options = { "sidebarbgcolor": "#A1ADCD", "sidebartextcolor": "black", "sidebarlinkcolor": "#334D5C", + "body_max_width": "1200px", } # Add any paths that contain custom themes here, relative to this directory. diff --git a/src/cython/doc/cubical_complex_ref.rst b/src/cython/doc/cubical_complex_ref.rst index 84aa4223..1fe9d5fb 100644 --- a/src/cython/doc/cubical_complex_ref.rst +++ b/src/cython/doc/cubical_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Cubical complex reference manual ################################ diff --git a/src/cython/doc/cubical_complex_sum.rst b/src/cython/doc/cubical_complex_sum.inc index 280ad0e0..280ad0e0 100644 --- a/src/cython/doc/cubical_complex_sum.rst +++ b/src/cython/doc/cubical_complex_sum.inc diff --git a/src/cython/doc/cubical_complex_user.rst b/src/cython/doc/cubical_complex_user.rst index dd82ad93..320bd79b 100644 --- a/src/cython/doc/cubical_complex_user.rst +++ b/src/cython/doc/cubical_complex_user.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Cubical complex user manual =========================== Definition @@ -144,6 +148,7 @@ the program output is: .. testoutput:: Periodic cubical complex is of dimension 2 - 42 simplices. + Examples. --------- diff --git a/src/cython/doc/euclidean_strong_witness_complex_ref.rst b/src/cython/doc/euclidean_strong_witness_complex_ref.rst index bebf0f9a..1a602cd5 100644 --- a/src/cython/doc/euclidean_strong_witness_complex_ref.rst +++ b/src/cython/doc/euclidean_strong_witness_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ================================================= Euclidean strong witness complex reference manual ================================================= diff --git a/src/cython/doc/euclidean_witness_complex_ref.rst b/src/cython/doc/euclidean_witness_complex_ref.rst index 29b8806f..28daf965 100644 --- a/src/cython/doc/euclidean_witness_complex_ref.rst +++ b/src/cython/doc/euclidean_witness_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ========================================== Euclidean witness complex reference manual ========================================== diff --git a/src/cython/doc/examples.rst b/src/cython/doc/examples.rst index 1e596e18..1f02f8a2 100644 --- a/src/cython/doc/examples.rst +++ b/src/cython/doc/examples.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Examples ######## @@ -19,3 +23,7 @@ Examples * :download:`rips_complex_diagram_persistence_from_distance_matrix_file_example.py <../example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py>` * :download:`rips_persistence_diagram.py <../example/rips_persistence_diagram.py>` * :download:`random_cubical_complex_persistence_example.py <../example/random_cubical_complex_persistence_example.py>` + * :download:`coordinate_graph_induced_complex.py <../example/coordinate_graph_induced_complex.py>` + * :download:`functional_graph_induced_complex.py <../example/functional_graph_induced_complex.py>` + * :download:`voronoi_graph_induced_complex.py <../example/voronoi_graph_induced_complex.py>` + * :download:`nerve_of_a_covering.py <../example/nerve_of_a_covering.py>` diff --git a/src/cython/doc/fileformats.rst b/src/cython/doc/fileformats.rst index 4f0b6f6d..ff20f26e 100644 --- a/src/cython/doc/fileformats.rst +++ b/src/cython/doc/fileformats.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + File formats ############ diff --git a/src/cython/doc/index.rst b/src/cython/doc/index.rst index 3945d72a..15cbe267 100644 --- a/src/cython/doc/index.rst +++ b/src/cython/doc/index.rst @@ -34,32 +34,37 @@ Data structures Alpha complex ============= -.. include:: alpha_complex_sum.rst +.. include:: alpha_complex_sum.inc + +Cover complexes +=============== + +.. include:: nerve_gic_complex_sum.rst Cubical complex =============== -.. include:: cubical_complex_sum.rst +.. include:: cubical_complex_sum.inc Rips complex ============ -.. include:: rips_complex_sum.rst +.. include:: rips_complex_sum.inc Simplex tree ============ -.. include:: simplex_tree_sum.rst +.. include:: simplex_tree_sum.inc Tangential complex ================== -.. include:: tangential_complex_sum.rst +.. include:: tangential_complex_sum.inc Witness complex =============== -.. include:: witness_complex_sum.rst +.. include:: witness_complex_sum.inc Toolbox @@ -68,17 +73,17 @@ Toolbox Bottleneck distance =================== -.. include:: bottleneck_distance_sum.rst +.. include:: bottleneck_distance_sum.inc Persistence cohomology ====================== -.. include:: persistent_cohomology_sum.rst +.. include:: persistent_cohomology_sum.inc Persistence graphical tools =========================== -.. include:: persistence_graphical_tools_sum.rst +.. include:: persistence_graphical_tools_sum.inc Bibliography ************ diff --git a/src/cython/doc/installation.rst b/src/cython/doc/installation.rst index c182f176..43576ec9 100644 --- a/src/cython/doc/installation.rst +++ b/src/cython/doc/installation.rst @@ -1,12 +1,16 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Installation ############ Compiling ********* - -The library uses c++11 and requires `Boost <http://www.boost.org/>`_ with -version 1.48.0 or more recent. It is a multi-platform library and compiles on -Linux, Mac OSX and Visual Studio 2015. +The library uses c++11 and requires `Boost <https://www.boost.org/>`_ ≥ 1.48.0 +and `CMake <https://www.cmake.org/>`_ ≥ 3.1. +It is a multi-platform library and compiles on Linux, Mac OSX and Visual +Studio 2015. It also requires cmake to generate makefiles, and cython to compile the library. @@ -43,6 +47,61 @@ following command in a terminal: export PYTHONPATH='$PYTHONPATH:/path-to-gudhi/build/cython' ctest -R py_test +Debugging issues +================ + +If tests fail, please check your PYTHONPATH and try to :code:`import gudhi` +and check the errors. +The problem can come from a third-party library bad link or installation. + +If :code:`import gudhi` succeeds, please have a look to debug informations: + +.. code-block:: python + + import gudhi + print(gudhi.__debug_info__) + +You shall have something like: + +.. code-block:: none + + Python version 2.7.15 + Cython version 0.26.1 + Eigen3 version 3.1.1 + Installed modules are: off_reader;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; + persistence_graphical_tools;reader_utils;witness_complex;strong_witness_complex;alpha_complex; + euclidean_witness_complex;euclidean_strong_witness_complex; + Missing modules are: bottleneck_distance;nerve_gic;subsampling;tangential_complex;persistence_graphical_tools; + CGAL version 4.7.1000 + GMP_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmp.so + GMPXX_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmpxx.so + TBB version 9107 found and used + +Here, you can see that bottleneck_distance, nerve_gic, subsampling and +tangential_complex are missing because of the CGAL version. +persistence_graphical_tools is not available as numpy and matplotlib are not +available. +Unitary tests cannot be run as pytest is missing. + +A complete configuration would be : + +.. code-block:: none + + Python version 3.6.5 + Cython version 0.28.2 + Pytest version 3.3.2 + Matplotlib version 2.2.2 + Numpy version 1.14.5 + Eigen3 version 3.3.4 + Installed modules are: off_reader;simplex_tree;rips_complex;cubical_complex;periodic_cubical_complex; + persistence_graphical_tools;reader_utils;witness_complex;strong_witness_complex;persistence_graphical_tools; + bottleneck_distance;nerve_gic;subsampling;tangential_complex;alpha_complex;euclidean_witness_complex; + euclidean_strong_witness_complex; + CGAL header only version 4.11.0 + GMP_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmp.so + GMPXX_LIBRARIES = /usr/lib/x86_64-linux-gnu/libgmpxx.so + TBB version 9107 found and used + Documentation ============= diff --git a/src/cython/doc/nerve_gic_complex_ref.rst b/src/cython/doc/nerve_gic_complex_ref.rst new file mode 100644 index 00000000..e24e01fc --- /dev/null +++ b/src/cython/doc/nerve_gic_complex_ref.rst @@ -0,0 +1,10 @@ +================================ +Cover complexes reference manual +================================ + +.. autoclass:: gudhi.CoverComplex + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: gudhi.CoverComplex.__init__ diff --git a/src/cython/doc/nerve_gic_complex_sum.rst b/src/cython/doc/nerve_gic_complex_sum.rst new file mode 100644 index 00000000..72782c7a --- /dev/null +++ b/src/cython/doc/nerve_gic_complex_sum.rst @@ -0,0 +1,15 @@ +================================================================= =================================== =================================== +:Author: Mathieu Carrière :Introduced in: GUDHI 2.1.0 :Copyright: GPL v3 +:Requires: CGAL :math:`\geq` 4.8.1 +================================================================= =================================== =================================== + ++----------------------------------------------------------------+------------------------------------------------------------------------+ +| .. figure:: | Nerves and Graph Induced Complexes are cover complexes, i.e. | +| ../../doc/Nerve_GIC/gicvisu.jpg | simplicial complexes that provably contain topological information | +| :alt: Graph Induced Complex of a point cloud. | about the input data. They can be computed with a cover of the data, | +| :figclass: align-center | that comes i.e. from the preimage of a family of intervals covering | +| | the image of a scalar-valued function defined on the data. | +| Graph Induced Complex of a point cloud. | | ++----------------------------------------------------------------+------------------------------------------------------------------------+ +| :doc:`nerve_gic_complex_user` | :doc:`nerve_gic_complex_ref` | ++----------------------------------------------------------------+------------------------------------------------------------------------+ diff --git a/src/cython/doc/nerve_gic_complex_user.rst b/src/cython/doc/nerve_gic_complex_user.rst new file mode 100644 index 00000000..d774827e --- /dev/null +++ b/src/cython/doc/nerve_gic_complex_user.rst @@ -0,0 +1,312 @@ +Cover complexes user manual +=========================== +Definition +---------- + +.. include:: nerve_gic_complex_sum.rst + +Visualizations of the simplicial complexes can be done with either +neato (from `graphviz <http://www.graphviz.org/>`_), +`geomview <http://www.geomview.org/>`_, +`KeplerMapper <https://github.com/MLWave/kepler-mapper>`_. +Input point clouds are assumed to be +`OFF files <http://www.geomview.org/docs/html/OFF.html>`_. + +Covers +------ + +Nerves and Graph Induced Complexes require a cover C of the input point cloud P, +that is a set of subsets of P whose union is P itself. +Very often, this cover is obtained from the preimage of a family of intervals covering +the image of some scalar-valued function f defined on P. This family is parameterized +by its resolution, which can be either the number or the length of the intervals, +and its gain, which is the overlap percentage between consecutive intervals (ordered by their first values). + +Nerves +------ + +Nerve definition +^^^^^^^^^^^^^^^^ + +Assume you are given a cover C of your point cloud P. Then, the Nerve of this cover +is the simplicial complex that has one k-simplex per k-fold intersection of cover elements. +See also `Wikipedia <https://en.wikipedia.org/wiki/Nerve_of_a_covering>`_. + +.. figure:: + ../../doc/Nerve_GIC/nerve.png + :figclass: align-center + :alt: Nerve of a double torus + + Nerve of a double torus + +Example +^^^^^^^ + +This example builds the Nerve of a point cloud sampled on a 3D human shape (human.off). +The cover C comes from the preimages of intervals (10 intervals with gain 0.3) +covering the height function (coordinate 2), +which are then refined into their connected components using the triangulation of the .OFF file. + +.. testcode:: + + import gudhi + nerve_complex = gudhi.CoverComplex() + nerve_complex.set_verbose(True) + + if (nerve_complex.read_point_cloud(gudhi.__root_source_dir__ + \ + '/data/points/human.off')): + nerve_complex.set_type('Nerve') + nerve_complex.set_color_from_coordinate(2) + nerve_complex.set_function_from_coordinate(2) + nerve_complex.set_graph_from_OFF() + nerve_complex.set_resolution_with_interval_number(10) + nerve_complex.set_gain(0.3) + nerve_complex.set_cover_from_function() + nerve_complex.find_simplices() + nerve_complex.write_info() + simplex_tree = nerve_complex.create_simplex_tree() + nerve_complex.compute_PD() + result_str = 'Nerve is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtration(): + print(filtered_value[0]) + +the program output is: + +.. code-block:: none + + Min function value = -0.979672 and Max function value = 0.816414 + Interval 0 = [-0.979672, -0.761576] + Interval 1 = [-0.838551, -0.581967] + Interval 2 = [-0.658942, -0.402359] + Interval 3 = [-0.479334, -0.22275] + Interval 4 = [-0.299725, -0.0431414] + Interval 5 = [-0.120117, 0.136467] + Interval 6 = [0.059492, 0.316076] + Interval 7 = [0.239101, 0.495684] + Interval 8 = [0.418709, 0.675293] + Interval 9 = [0.598318, 0.816414] + Computing preimages... + Computing connected components... + 5 interval(s) in dimension 0: + [-0.909111, 0.0081753] + [-0.171433, 0.367393] + [-0.171433, 0.367393] + [-0.909111, 0.745853] + 0 interval(s) in dimension 1: + +.. testoutput:: + + Nerve is of dimension 1 - 41 simplices - 21 vertices. + [0] + [1] + [4] + [1, 4] + [2] + [0, 2] + [8] + [2, 8] + [5] + [4, 5] + [9] + [8, 9] + [13] + [5, 13] + [14] + [9, 14] + [19] + [13, 19] + [25] + [32] + [20] + [20, 32] + [33] + [25, 33] + [26] + [14, 26] + [19, 26] + [42] + [26, 42] + [34] + [33, 34] + [27] + [20, 27] + [35] + [27, 35] + [34, 35] + [35, 42] + [44] + [35, 44] + [54] + [44, 54] + + +The program also writes a file ../../data/points/human.off_sc.txt. The first +three lines in this file are the location of the input point cloud and the +function used to compute the cover. +The fourth line contains the number of vertices nv and edges ne of the Nerve. +The next nv lines represent the vertices. Each line contains the vertex ID, +the number of data points it contains, and their average color function value. +Finally, the next ne lines represent the edges, characterized by the ID of +their vertices. + +Using KeplerMapper, one can obtain the following visualization: + +.. figure:: + ../../doc/Nerve_GIC/nervevisu.jpg + :figclass: align-center + :alt: Visualization with KeplerMapper + + Visualization with KeplerMapper + +Graph Induced Complexes (GIC) +----------------------------- + +GIC definition +^^^^^^^^^^^^^^ + +Again, assume you are given a cover C of your point cloud P. Moreover, assume +you are also given a graph G built on top of P. Then, for any clique in G +whose nodes all belong to different elements of C, the GIC includes a +corresponding simplex, whose dimension is the number of nodes in the clique +minus one. +See :cite:`Dey13` for more details. + +.. figure:: + ../../doc/Nerve_GIC/GIC.jpg + :figclass: align-center + :alt: GIC of a point cloud + + GIC of a point cloud + +Example with cover from Voronoï +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This example builds the GIC of a point cloud sampled on a 3D human shape +(human.off). +We randomly subsampled 100 points in the point cloud, which act as seeds of +a geodesic Voronoï diagram. Each cell of the diagram is then an element of C. +The graph G (used to compute both the geodesics for Voronoï and the GIC) +comes from the triangulation of the human shape. Note that the resulting +simplicial complex is in dimension 3 in this example. + +.. testcode:: + + import gudhi + nerve_complex = gudhi.CoverComplex() + + if (nerve_complex.read_point_cloud(gudhi.__root_source_dir__ + \ + '/data/points/human.off')): + nerve_complex.set_type('GIC') + nerve_complex.set_color_from_coordinate() + nerve_complex.set_graph_from_OFF() + nerve_complex.set_cover_from_Voronoi(700) + nerve_complex.find_simplices() + nerve_complex.plot_off() + +the program outputs SC.off. Using e.g. + +.. code-block:: none + + geomview ../../data/points/human.off_sc.off + +one can obtain the following visualization: + +.. figure:: + ../../doc/Nerve_GIC/gicvoronoivisu.jpg + :figclass: align-center + :alt: Visualization with Geomview + + Visualization with Geomview + +Functional GIC +^^^^^^^^^^^^^^ + +If one restricts to the cliques in G whose nodes all belong to preimages of +consecutive intervals (assuming the cover of the height function is minimal, +i.e. no more than two intervals can intersect at a time), the GIC is of +dimension one, i.e. a graph. +We call this graph the functional GIC. See :cite:`Carriere16` for more details. + +Example +^^^^^^^ + +Functional GIC comes with automatic selection of the Rips threshold, +the resolution and the gain of the function cover. See :cite:`Carriere17c` for +more details. In this example, we compute the functional GIC of a Klein bottle +embedded in R^5, where the graph G comes from a Rips complex with automatic +threshold, and the cover C comes from the preimages of intervals covering the +first coordinate, with automatic resolution and gain. Note that automatic +threshold, resolution and gain can be computed as well for the Nerve. + +.. testcode:: + + import gudhi + nerve_complex = gudhi.CoverComplex() + + if (nerve_complex.read_point_cloud(gudhi.__root_source_dir__ + \ + '/data/points/KleinBottle5D.off')): + nerve_complex.set_type('GIC') + nerve_complex.set_color_from_coordinate(0) + nerve_complex.set_function_from_coordinate(0) + nerve_complex.set_graph_from_automatic_rips() + nerve_complex.set_automatic_resolution() + nerve_complex.set_gain() + nerve_complex.set_cover_from_function() + nerve_complex.find_simplices() + nerve_complex.plot_dot() + +the program outputs SC.dot. Using e.g. + +.. code-block:: none + + neato ../../data/points/KleinBottle5D.off_sc.dot -Tpdf -o ../../data/points/KleinBottle5D.off_sc.pdf + +one can obtain the following visualization: + +.. figure:: + ../../doc/Nerve_GIC/coordGICvisu2.jpg + :figclass: align-center + :alt: Visualization with neato + + Visualization with neato + +where nodes are colored by the filter function values and, for each node, the +first number is its ID and the second is the number of data points that its +contain. + +We also provide an example on a set of 72 pictures taken around the same object +(lucky_cat.off). +The function is now the first eigenfunction given by PCA, whose values are +written in a file (lucky_cat_PCA1). Threshold, resolution and gain are +automatically selected as before. + +.. testcode:: + + import gudhi + nerve_complex = gudhi.CoverComplex() + + if (nerve_complex.read_point_cloud(gudhi.__root_source_dir__ + \ + '/data/points/COIL_database/lucky_cat.off')): + nerve_complex.set_type('GIC') + pca_file = gudhi.__root_source_dir__ + \ + '/data/points/COIL_database/lucky_cat_PCA1' + nerve_complex.set_color_from_file(pca_file) + nerve_complex.set_function_from_file(pca_file) + nerve_complex.set_graph_from_automatic_rips() + nerve_complex.set_automatic_resolution() + nerve_complex.set_gain() + nerve_complex.set_cover_from_function() + nerve_complex.find_simplices() + nerve_complex.plot_dot() + +the program outputs again SC.dot which gives the following visualization after using neato: + +.. figure:: + ../../doc/Nerve_GIC/funcGICvisu.jpg + :figclass: align-center + :alt: Visualization with neato + + Visualization with neato diff --git a/src/cython/doc/periodic_cubical_complex_ref.rst b/src/cython/doc/periodic_cubical_complex_ref.rst index c6190a1b..4b831647 100644 --- a/src/cython/doc/periodic_cubical_complex_ref.rst +++ b/src/cython/doc/periodic_cubical_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Periodic cubical complex reference manual ######################################### diff --git a/src/cython/doc/persistence_graphical_tools_ref.rst b/src/cython/doc/persistence_graphical_tools_ref.rst index 27c2f68a..a2c6bcef 100644 --- a/src/cython/doc/persistence_graphical_tools_ref.rst +++ b/src/cython/doc/persistence_graphical_tools_ref.rst @@ -1,8 +1,11 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ============================================ Persistence graphical tools reference manual ============================================ .. autofunction:: gudhi.__min_birth_max_death -.. autofunction:: gudhi.show_palette_values .. autofunction:: gudhi.plot_persistence_barcode .. autofunction:: gudhi.plot_persistence_diagram diff --git a/src/cython/doc/persistence_graphical_tools_sum.rst b/src/cython/doc/persistence_graphical_tools_sum.inc index d602daa7..d602daa7 100644 --- a/src/cython/doc/persistence_graphical_tools_sum.rst +++ b/src/cython/doc/persistence_graphical_tools_sum.inc diff --git a/src/cython/doc/persistence_graphical_tools_user.rst b/src/cython/doc/persistence_graphical_tools_user.rst index a5523d23..292915eb 100644 --- a/src/cython/doc/persistence_graphical_tools_user.rst +++ b/src/cython/doc/persistence_graphical_tools_user.rst @@ -1,49 +1,26 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Persistence graphical tools user manual ======================================= Definition ---------- -.. include:: persistence_graphical_tools_sum.rst - - -Show palette values -------------------- - -This function is useful to show the color palette values of dimension: - +.. include:: persistence_graphical_tools_sum.inc -.. testcode:: - - import gudhi - plt = gudhi.show_palette_values(alpha=1.0) - plt.show() - -.. plot:: - - import gudhi - plt = gudhi.show_palette_values(alpha=1.0) - plt.show() Show persistence as a barcode ----------------------------- This function can display the persistence result as a barcode: -.. testcode:: - - import gudhi - - periodic_cc = gudhi.PeriodicCubicalComplex(perseus_file=gudhi.__root_source_dir__ + \ - '/data/bitmap/3d_torus.txt') - diag = periodic_cc.persistence() - plt = gudhi.plot_persistence_barcode(diag) - plt.show() - .. plot:: + :include-source: import gudhi - periodic_cc = gudhi.PeriodicCubicalComplex(perseus_file=gudhi.__root_source_dir__ + \ - '/data/bitmap/3d_torus.txt') + perseus_file = gudhi.__root_source_dir__ + '/data/bitmap/3d_torus.txt' + periodic_cc = gudhi.PeriodicCubicalComplex(perseus_file=perseus_file) diag = periodic_cc.persistence() print("diag = ", diag) plt = gudhi.plot_persistence_barcode(diag) @@ -54,24 +31,32 @@ Show persistence as a diagram This function can display the persistence result as a diagram: -.. testcode:: +.. plot:: + :include-source: import gudhi - - point_cloud = gudhi.read_off(off_file=gudhi.__root_source_dir__ + '/data/points/tore3D_1307.off') - rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=0.2) - simplex_tree = rips_complex.create_simplex_tree(max_dimension=3) - diag = simplex_tree.persistence() - plt = gudhi.plot_persistence_diagram(diag, band_boot=0.13) + + # rips_on_tore3D_1307.pers obtained from write_persistence_diagram method + persistence_file=gudhi.__root_source_dir__ + \ + '/data/persistence_diagram/rips_on_tore3D_1307.pers' + plt = gudhi.plot_persistence_diagram(persistence_file=persistence_file, + legend=True) plt.show() +If you want more information on a specific dimension, for instance: + .. plot:: + :include-source: import gudhi - point_cloud = gudhi.read_off(off_file=gudhi.__root_source_dir__ + '/data/points/tore3D_1307.off') - rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=0.2) - simplex_tree = rips_complex.create_simplex_tree(max_dimension=3) - diag = simplex_tree.persistence() - plt = gudhi.plot_persistence_diagram(diag, band_boot=0.13) + persistence_file=gudhi.__root_source_dir__ + \ + '/data/persistence_diagram/rips_on_tore3D_1307.pers' + diag = \ + gudhi.read_persistence_intervals_grouped_by_dimension(persistence_file=\ + persistence_file) + dim = 1 + # Display all points with some transparency + plt = gudhi.plot_persistence_diagram([(dim,interval) for interval in diag[dim]], + max_plots=0, alpha=0.1) plt.show() diff --git a/src/cython/doc/persistent_cohomology_sum.rst b/src/cython/doc/persistent_cohomology_sum.inc index a26df1dc..a26df1dc 100644 --- a/src/cython/doc/persistent_cohomology_sum.rst +++ b/src/cython/doc/persistent_cohomology_sum.inc diff --git a/src/cython/doc/persistent_cohomology_user.rst b/src/cython/doc/persistent_cohomology_user.rst index bf90c163..ce7fc685 100644 --- a/src/cython/doc/persistent_cohomology_user.rst +++ b/src/cython/doc/persistent_cohomology_user.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Persistent cohomology user manual ================================= Definition diff --git a/src/cython/doc/pyplots/barcode_persistence.py b/src/cython/doc/pyplots/barcode_persistence.py deleted file mode 100755 index de33d506..00000000 --- a/src/cython/doc/pyplots/barcode_persistence.py +++ /dev/null @@ -1,7 +0,0 @@ -import gudhi - -periodic_cc = gudhi.PeriodicCubicalComplex(perseus_file=gudhi.__root_source_dir__ + \ - '/data/bitmap/3d_torus.txt') -diag = periodic_cc.persistence() -plt = gudhi.plot_persistence_barcode(diag) -plt.show() diff --git a/src/cython/doc/pyplots/diagram_persistence.py b/src/cython/doc/pyplots/diagram_persistence.py deleted file mode 100755 index ac20bf47..00000000 --- a/src/cython/doc/pyplots/diagram_persistence.py +++ /dev/null @@ -1,9 +0,0 @@ -import gudhi - -point_cloud = gudhi.read_off(off_file=gudhi.__root_source_dir__ + \ - '/data/points/tore3D_1307.off') -rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=0.2) -simplex_tree = rips_complex.create_simplex_tree(max_dimension=3) -diag = simplex_tree.persistence() -plt = gudhi.plot_persistence_diagram(diag, band_boot=0.13) -plt.show() diff --git a/src/cython/doc/pyplots/show_palette_values.py b/src/cython/doc/pyplots/show_palette_values.py deleted file mode 100755 index fdf9645f..00000000 --- a/src/cython/doc/pyplots/show_palette_values.py +++ /dev/null @@ -1,3 +0,0 @@ -import gudhi -plt = gudhi.show_palette_values(alpha=1.0) -plt.show() diff --git a/src/cython/doc/reader_utils_ref.rst b/src/cython/doc/reader_utils_ref.rst index 9c1ea6fc..f3ecebad 100644 --- a/src/cython/doc/reader_utils_ref.rst +++ b/src/cython/doc/reader_utils_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ============================= Reader utils reference manual ============================= diff --git a/src/cython/doc/rips_complex_ref.rst b/src/cython/doc/rips_complex_ref.rst index b17dc4e0..22b5616c 100644 --- a/src/cython/doc/rips_complex_ref.rst +++ b/src/cython/doc/rips_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ============================= Rips complex reference manual ============================= diff --git a/src/cython/doc/rips_complex_sum.rst b/src/cython/doc/rips_complex_sum.inc index 5616bfa9..5616bfa9 100644 --- a/src/cython/doc/rips_complex_sum.rst +++ b/src/cython/doc/rips_complex_sum.inc diff --git a/src/cython/doc/rips_complex_user.rst b/src/cython/doc/rips_complex_user.rst index 7738aef0..a8c06cf9 100644 --- a/src/cython/doc/rips_complex_user.rst +++ b/src/cython/doc/rips_complex_user.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Rips complex user manual ========================= Definition @@ -243,7 +247,7 @@ the program output is: [3, 6] -> 11.00 Correlation matrix ---------------- +------------------ Example from a correlation matrix ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/cython/doc/simplex_tree_ref.rst b/src/cython/doc/simplex_tree_ref.rst index 6d196843..9eb8c199 100644 --- a/src/cython/doc/simplex_tree_ref.rst +++ b/src/cython/doc/simplex_tree_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ============================= Simplex tree reference manual ============================= diff --git a/src/cython/doc/simplex_tree_sum.rst b/src/cython/doc/simplex_tree_sum.inc index fb0e54c1..fb0e54c1 100644 --- a/src/cython/doc/simplex_tree_sum.rst +++ b/src/cython/doc/simplex_tree_sum.inc diff --git a/src/cython/doc/simplex_tree_user.rst b/src/cython/doc/simplex_tree_user.rst index 4b1dde19..aebeb29f 100644 --- a/src/cython/doc/simplex_tree_user.rst +++ b/src/cython/doc/simplex_tree_user.rst @@ -1,9 +1,13 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Simplex tree user manual ======================== Definition ---------- -.. include:: simplex_tree_sum.rst +.. include:: simplex_tree_sum.inc A simplicial complex :math:`\mathbf{K}` on a set of vertices :math:`V = \{1, \cdots ,|V|\}` is a collection of simplices :math:`\{\sigma\}`, :math:`\sigma \subseteq V` such that diff --git a/src/cython/doc/strong_witness_complex_ref.rst b/src/cython/doc/strong_witness_complex_ref.rst index 4ed4fe46..d624d711 100644 --- a/src/cython/doc/strong_witness_complex_ref.rst +++ b/src/cython/doc/strong_witness_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ======================================= Strong witness complex reference manual ======================================= diff --git a/src/cython/doc/tangential_complex_ref.rst b/src/cython/doc/tangential_complex_ref.rst index 35589475..cdfda082 100644 --- a/src/cython/doc/tangential_complex_ref.rst +++ b/src/cython/doc/tangential_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + =================================== Tangential complex reference manual =================================== diff --git a/src/cython/doc/tangential_complex_sum.rst b/src/cython/doc/tangential_complex_sum.inc index 72b4d7ba..72b4d7ba 100644 --- a/src/cython/doc/tangential_complex_sum.rst +++ b/src/cython/doc/tangential_complex_sum.inc diff --git a/src/cython/doc/tangential_complex_user.rst b/src/cython/doc/tangential_complex_user.rst index efa6d7ce..5ce69e86 100644 --- a/src/cython/doc/tangential_complex_user.rst +++ b/src/cython/doc/tangential_complex_user.rst @@ -1,6 +1,10 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Tangential complex user manual ============================== -.. include:: tangential_complex_sum.rst +.. include:: tangential_complex_sum.inc Definition ---------- @@ -122,8 +126,8 @@ This example builds the Tangential complex of point set read in an OFF file. .. testcode:: import gudhi - tc = gudhi.TangentialComplex(off_file=gudhi.__root_source_dir__ + \ - '/data/points/alphacomplexdoc.off') + tc = gudhi.TangentialComplex(intrisic_dim = 1, + off_file=gudhi.__root_source_dir__ + '/data/points/alphacomplexdoc.off') result_str = 'Tangential contains ' + repr(tc.num_simplices()) + \ ' simplices - ' + repr(tc.num_vertices()) + ' vertices.' print(result_str) @@ -169,7 +173,8 @@ simplices. .. testcode:: import gudhi - tc = gudhi.TangentialComplex(points=[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]]) + tc = gudhi.TangentialComplex(intrisic_dim = 1, + points=[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]]) result_str = 'Tangential contains ' + repr(tc.num_vertices()) + ' vertices.' print(result_str) diff --git a/src/cython/doc/todos.rst b/src/cython/doc/todos.rst index 78972a4c..ca274ced 100644 --- a/src/cython/doc/todos.rst +++ b/src/cython/doc/todos.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ========== To be done ========== diff --git a/src/cython/doc/witness_complex_ref.rst b/src/cython/doc/witness_complex_ref.rst index c78760cb..9987d3fd 100644 --- a/src/cython/doc/witness_complex_ref.rst +++ b/src/cython/doc/witness_complex_ref.rst @@ -1,3 +1,7 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + ================================ Witness complex reference manual ================================ diff --git a/src/cython/doc/witness_complex_sum.rst b/src/cython/doc/witness_complex_sum.inc index a8a126a0..a8a126a0 100644 --- a/src/cython/doc/witness_complex_sum.rst +++ b/src/cython/doc/witness_complex_sum.inc diff --git a/src/cython/doc/witness_complex_user.rst b/src/cython/doc/witness_complex_user.rst index 99be5185..40e94134 100644 --- a/src/cython/doc/witness_complex_user.rst +++ b/src/cython/doc/witness_complex_user.rst @@ -1,7 +1,11 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + Witness complex user manual =========================== -.. include:: witness_complex_sum.rst +.. include:: witness_complex_sum.inc Definitions ----------- diff --git a/src/cython/example/alpha_complex_diagram_persistence_from_off_file_example.py b/src/cython/example/alpha_complex_diagram_persistence_from_off_file_example.py index 27550025..4abe22d4 100755 --- a/src/cython/example/alpha_complex_diagram_persistence_from_off_file_example.py +++ b/src/cython/example/alpha_complex_diagram_persistence_from_off_file_example.py @@ -38,7 +38,7 @@ parser = argparse.ArgumentParser(description='AlphaComplex creation from ' 'points from the given OFF file.') parser.add_argument("-f", "--file", type=str, required=True) parser.add_argument("-a", "--max_alpha_square", type=float, default=0.5) -parser.add_argument("-b", "--band_boot", type=float, default=0.) +parser.add_argument("-b", "--band", 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() @@ -64,7 +64,7 @@ with open(args.file, 'r') as f: print(simplex_tree.betti_numbers()) if args.no_diagram == False: - pplot = gudhi.plot_persistence_diagram(diag, band_boot=args.band_boot) + pplot = gudhi.plot_persistence_diagram(diag, band=args.band) pplot.show() else: print(args.file, "is not a valid OFF file") diff --git a/src/cython/example/coordinate_graph_induced_complex.py b/src/cython/example/coordinate_graph_induced_complex.py new file mode 100755 index 00000000..9e93109a --- /dev/null +++ b/src/cython/example/coordinate_graph_induced_complex.py @@ -0,0 +1,68 @@ +#!/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) 2018 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) 2018 Inria" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='Coordinate GIC ' + 'from points read in a OFF file.', + epilog='Example: ' + 'example/coordinate_graph_induced_complex.py ' + '-f ../data/points/KleinBottle5D.off -c 0 -v' + '- Constructs the coordinate GIC with the ' + 'points from the given OFF file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-c", "--coordinate", type=int, default=0) +parser.add_argument("-v", "--verbose", default=False, action='store_true' , help='Flag for program verbosity') + +args = parser.parse_args() + +nerve_complex = gudhi.CoverComplex() +nerve_complex.set_verbose(args.verbose) + +if (nerve_complex.read_point_cloud(args.file)): + nerve_complex.set_type('GIC') + nerve_complex.set_color_from_coordinate(args.coordinate) + nerve_complex.set_function_from_coordinate(args.coordinate) + nerve_complex.set_graph_from_automatic_rips() + nerve_complex.set_automatic_resolution() + nerve_complex.set_gain() + nerve_complex.set_cover_from_function() + nerve_complex.find_simplices() + nerve_complex.plot_dot() + simplex_tree = nerve_complex.create_simplex_tree() + nerve_complex.compute_PD() + if (args.verbose): + print('Iterator on coordinate GIC simplices') + result_str = 'Coordinate GIC is of dimension ' + \ + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtration(): + print(filtered_value[0]) diff --git a/src/cython/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py b/src/cython/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py index 1c142d9a..3b29781f 100755 --- a/src/cython/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py +++ b/src/cython/example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py @@ -40,7 +40,7 @@ parser.add_argument("-f", "--file", type=str, required=True) parser.add_argument("-a", "--max_alpha_square", type=float, required=True) parser.add_argument("-n", "--number_of_landmarks", type=int, required=True) parser.add_argument("-d", "--limit_dimension", type=int, required=True) -parser.add_argument("-b", "--band_boot", type=float, default=0.) +parser.add_argument("-b", "--band", 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() @@ -71,7 +71,7 @@ with open(args.file, 'r') as f: print(simplex_tree.betti_numbers()) if args.no_diagram == False: - pplot = gudhi.plot_persistence_diagram(diag, band_boot=args.band_boot) + pplot = gudhi.plot_persistence_diagram(diag, band=args.band) pplot.show() else: print(args.file, "is not a valid OFF file") diff --git a/src/cython/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py b/src/cython/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py index 216fcff2..db34962d 100755 --- a/src/cython/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py +++ b/src/cython/example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py @@ -40,7 +40,7 @@ parser.add_argument("-f", "--file", type=str, required=True) parser.add_argument("-a", "--max_alpha_square", type=float, required=True) parser.add_argument("-n", "--number_of_landmarks", type=int, required=True) parser.add_argument("-d", "--limit_dimension", type=int, required=True) -parser.add_argument("-b", "--band_boot", type=float, default=0.) +parser.add_argument("-b", "--band", 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() @@ -71,7 +71,7 @@ with open(args.file, 'r') as f: print(simplex_tree.betti_numbers()) if args.no_diagram == False: - pplot = gudhi.plot_persistence_diagram(diag, band_boot=args.band_boot) + pplot = gudhi.plot_persistence_diagram(diag, band=args.band) pplot.show() else: print(args.file, "is not a valid OFF file") diff --git a/src/cython/example/functional_graph_induced_complex.py b/src/cython/example/functional_graph_induced_complex.py new file mode 100755 index 00000000..6ad7c2ec --- /dev/null +++ b/src/cython/example/functional_graph_induced_complex.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) 2018 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) 2018 Inria" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='Functional GIC ' + 'from points read in a OFF file.', + epilog='Example: ' + 'example/functional_graph_induced_complex.py ' + '-o ../data/points/COIL_database/lucky_cat.off ' + '-f ../data/points/COIL_database/lucky_cat_PCA1' + '- Constructs the functional GIC with the ' + 'points from the given OFF and function files.') +parser.add_argument("-o", "--off-file", type=str, required=True) +parser.add_argument("-f", "--function-file", type=str, required=True) +parser.add_argument("-v", "--verbose", default=False, action='store_true' , help='Flag for program verbosity') + +args = parser.parse_args() + +nerve_complex = gudhi.CoverComplex() +nerve_complex.set_verbose(args.verbose) + +if (nerve_complex.read_point_cloud(args.off_file)): + nerve_complex.set_type('GIC') + nerve_complex.set_color_from_file(args.function_file) + nerve_complex.set_function_from_file(args.function_file) + nerve_complex.set_graph_from_automatic_rips() + nerve_complex.set_automatic_resolution() + nerve_complex.set_gain() + nerve_complex.set_cover_from_function() + nerve_complex.find_simplices() + nerve_complex.plot_dot() + simplex_tree = nerve_complex.create_simplex_tree() + nerve_complex.compute_PD() + if (args.verbose): + print('Iterator on functional GIC simplices') + result_str = 'Functional GIC is of dimension ' + \ + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtration(): + print(filtered_value[0]) diff --git a/src/cython/example/gudhi_graphical_tools_example.py b/src/cython/example/gudhi_graphical_tools_example.py index 9f37efc0..ac3d146c 100755 --- a/src/cython/example/gudhi_graphical_tools_example.py +++ b/src/cython/example/gudhi_graphical_tools_example.py @@ -29,11 +29,6 @@ __copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" print("#####################################################################") -print("Show palette colors values for dimension") - -gudhi.show_palette_values() - -print("#####################################################################") print("Show barcode persistence example") persistence = [(2, (1.0, float('inf'))), (1, (1.4142135623730951, float('inf'))), @@ -50,5 +45,5 @@ pplot.show() print("#####################################################################") print("Show diagram persistence example with a confidence band") -pplot = gudhi.plot_persistence_diagram(persistence, band_boot=0.2) +pplot = gudhi.plot_persistence_diagram(persistence, band=0.2) pplot.show() diff --git a/src/cython/example/nerve_of_a_covering.py b/src/cython/example/nerve_of_a_covering.py new file mode 100755 index 00000000..c5577cb1 --- /dev/null +++ b/src/cython/example/nerve_of_a_covering.py @@ -0,0 +1,70 @@ +#!/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) 2018 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) 2018 Inria" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='Nerve of a covering creation ' + 'from points read in a OFF file.', + epilog='Example: ' + 'example/nerve_of_a_covering.py ' + '-f ../data/points/human.off -c 2 -r 10 -g 0.3' + '- Constructs Nerve of a covering with the ' + 'points from the given OFF file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-c", "--coordinate", type=int, default=0) +parser.add_argument("-r", "--resolution", type=int, default=10) +parser.add_argument("-g", "--gain", type=float, default=0.3) +parser.add_argument("-v", "--verbose", default=False, action='store_true' , help='Flag for program verbosity') + +args = parser.parse_args() + +nerve_complex = gudhi.CoverComplex() +nerve_complex.set_verbose(args.verbose) + +if (nerve_complex.read_point_cloud(args.file)): + nerve_complex.set_type('Nerve') + nerve_complex.set_color_from_coordinate(args.coordinate) + nerve_complex.set_function_from_coordinate(args.coordinate) + nerve_complex.set_graph_from_OFF() + nerve_complex.set_resolution_with_interval_number(args.resolution) + nerve_complex.set_gain(args.gain) + nerve_complex.set_cover_from_function() + nerve_complex.find_simplices() + nerve_complex.write_info() + simplex_tree = nerve_complex.create_simplex_tree() + nerve_complex.compute_PD() + if (args.verbose): + print('Iterator on graph induced complex simplices') + result_str = 'Nerve is of dimension ' + \ + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtration(): + print(filtered_value[0]) 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 index 4142fa99..0c9dfc43 100755 --- 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 @@ -40,7 +40,7 @@ parser = argparse.ArgumentParser(description='RipsComplex creation from ' parser.add_argument("-f", "--file", type=str, required=True) parser.add_argument("-c", "--min_edge_correlation", 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("-b", "--band", 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() @@ -80,5 +80,5 @@ print(simplex_tree.betti_numbers()) invert_diag = [(diag[pers][0],(1.-diag[pers][1][0], 1.-diag[pers][1][1])) for pers in range(len(diag))] if args.no_diagram == False: - pplot = gudhi.plot_persistence_diagram(invert_diag, band_boot=args.band_boot) + pplot = gudhi.plot_persistence_diagram(invert_diag, band=args.band) 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 01d1f38a..4d2ed577 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 @@ -39,7 +39,7 @@ parser = argparse.ArgumentParser(description='RipsComplex creation from ' 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("-b", "--band", 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() @@ -63,5 +63,5 @@ 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 = gudhi.plot_persistence_diagram(diag, band=args.band) pplot.show() diff --git a/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py b/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py index 865c66b6..d15d5eb0 100755 --- a/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py +++ b/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py @@ -39,7 +39,7 @@ parser = argparse.ArgumentParser(description='RipsComplex creation from ' 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("-b", "--band", 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() @@ -66,7 +66,7 @@ with open(args.file, 'r') as f: print(simplex_tree.betti_numbers()) if args.no_diagram == False: - pplot = gudhi.plot_persistence_diagram(diag, band_boot=args.band_boot) + pplot = gudhi.plot_persistence_diagram(diag, band=args.band) pplot.show() else: print(args.file, "is not a valid OFF file") diff --git a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py index 680a8bf8..0f8f5e80 100755 --- a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py +++ b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py @@ -33,11 +33,12 @@ parser = argparse.ArgumentParser(description='TangentialComplex creation from ' 'points read in a OFF file.', epilog='Example: ' 'example/tangential_complex_plain_homology_from_off_file_example.py ' - '-f ../data/points/tore3D_300.off' + '-f ../data/points/tore3D_300.off -i 3' '- Constructs a tangential complex with the ' 'points from the given OFF file') parser.add_argument("-f", "--file", type=str, required=True) -parser.add_argument("-b", "--band_boot", type=float, default=0.) +parser.add_argument("-i", "--intrisic_dim", type=int, required=True) +parser.add_argument("-b", "--band", 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() @@ -48,7 +49,7 @@ with open(args.file, 'r') as f: print("#####################################################################") print("TangentialComplex creation from points read in a OFF file") - tc = gudhi.TangentialComplex(off_file=args.file) + tc = gudhi.TangentialComplex(intrisic_dim = args.intrisic_dim, off_file=args.file) st = tc.create_simplex_tree() message = "Number of simplices=" + repr(st.num_simplices()) @@ -60,7 +61,7 @@ with open(args.file, 'r') as f: print(st.betti_numbers()) if args.no_diagram == False: - pplot = gudhi.plot_persistence_diagram(diag, band_boot=args.band_boot) + pplot = gudhi.plot_persistence_diagram(diag, band=args.band) pplot.show() else: print(args.file, "is not a valid OFF file") diff --git a/src/cython/example/voronoi_graph_induced_complex.py b/src/cython/example/voronoi_graph_induced_complex.py new file mode 100755 index 00000000..8266a0e4 --- /dev/null +++ b/src/cython/example/voronoi_graph_induced_complex.py @@ -0,0 +1,65 @@ +#!/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) 2018 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) 2018 Inria" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='Voronoi GIC ' + 'from points read in a OFF file.', + epilog='Example: ' + 'example/voronoi_graph_induced_complex.py ' + '-f ../data/points/human.off -n 700 -v' + '- Constructs the Voronoi GIC with the ' + 'points from the given OFF file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-n", "--subsample-nb-points", type=int, default=100) +parser.add_argument("-v", "--verbose", default=False, action='store_true' , help='Flag for program verbosity') + +args = parser.parse_args() + +nerve_complex = gudhi.CoverComplex() +nerve_complex.set_verbose(args.verbose) + +if (nerve_complex.read_point_cloud(args.file)): + nerve_complex.set_type('GIC') + nerve_complex.set_color_from_coordinate() + nerve_complex.set_graph_from_OFF() + nerve_complex.set_cover_from_Voronoi(args.subsample_nb_points) + nerve_complex.find_simplices() + nerve_complex.plot_off() + simplex_tree = nerve_complex.create_simplex_tree() + nerve_complex.compute_PD() + if (args.verbose): + print('Iterator on graph induced complex simplices') + result_str = 'Graph induced complex is of dimension ' + \ + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtration(): + print(filtered_value[0]) diff --git a/src/cython/gudhi.pyx.in b/src/cython/gudhi.pyx.in index b94f2251..0d4b966b 100644 --- a/src/cython/gudhi.pyx.in +++ b/src/cython/gudhi.pyx.in @@ -26,6 +26,7 @@ __license__ = "GPL v3" __version__ = "@GUDHI_VERSION@" # This variable is used by doctest to find files __root_source_dir__ = "@CMAKE_SOURCE_DIR@" +__debug_info__ = @GUDHI_CYTHON_DEBUG_INFO@ include '@CMAKE_CURRENT_SOURCE_DIR@/cython/off_reader.pyx' include '@CMAKE_CURRENT_SOURCE_DIR@/cython/simplex_tree.pyx' @@ -41,3 +42,4 @@ include '@CMAKE_CURRENT_SOURCE_DIR@/cython/strong_witness_complex.pyx' @GUDHI_CYTHON_SUBSAMPLING@ @GUDHI_CYTHON_TANGENTIAL_COMPLEX@ @GUDHI_CYTHON_BOTTLENECK_DISTANCE@ +@GUDHI_CYTHON_NERVE_GIC@ diff --git a/src/cython/include/Nerve_gic_interface.h b/src/cython/include/Nerve_gic_interface.h new file mode 100644 index 00000000..aa71e2a6 --- /dev/null +++ b/src/cython/include/Nerve_gic_interface.h @@ -0,0 +1,61 @@ +/* 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) 2018 Inria + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDE_NERVE_GIC_INTERFACE_H_ +#define INCLUDE_NERVE_GIC_INTERFACE_H_ + +#include <gudhi/Simplex_tree.h> +#include <gudhi/distance_functions.h> +#include <gudhi/GIC.h> + +#include "Simplex_tree_interface.h" + +#include <iostream> +#include <vector> +#include <string> + +namespace Gudhi { + +namespace cover_complex { + +class Nerve_gic_interface : public Cover_complex<std::vector<double>> { + public: + void create_simplex_tree(Simplex_tree_interface<>* simplex_tree) { + create_complex(*simplex_tree); + simplex_tree->initialize_filtration(); + } + void set_cover_from_Euclidean_Voronoi(int m) { + set_cover_from_Voronoi(Gudhi::Euclidean_distance(), m); + } + double set_graph_from_automatic_euclidean_rips(int N) { + return set_graph_from_automatic_rips(Gudhi::Euclidean_distance(), N); + } + void set_graph_from_euclidean_rips(double threshold) { + set_graph_from_rips(threshold, Gudhi::Euclidean_distance()); + } +}; + +} // namespace cover_complex + +} // namespace Gudhi + +#endif // INCLUDE_NERVE_GIC_INTERFACE_H_ diff --git a/src/cython/include/Persistent_cohomology_interface.h b/src/cython/include/Persistent_cohomology_interface.h index a86b1187..8cf71a4e 100644 --- a/src/cython/include/Persistent_cohomology_interface.h +++ b/src/cython/include/Persistent_cohomology_interface.h @@ -85,6 +85,32 @@ persistent_cohomology::Persistent_cohomology<FilteredComplex, persistent_cohomol return persistence; } + std::vector<std::pair<std::vector<int>, std::vector<int>>> persistence_pairs() { + auto pairs = persistent_cohomology::Persistent_cohomology<FilteredComplex, + persistent_cohomology::Field_Zp>::get_persistent_pairs(); + + std::vector<std::pair<std::vector<int>, std::vector<int>>> persistence_pairs; + persistence_pairs.reserve(pairs.size()); + for (auto pair : pairs) { + std::vector<int> birth; + if (get<0>(pair) != stptr_->null_simplex()) { + for (auto vertex : stptr_->simplex_vertex_range(get<0>(pair))) { + birth.push_back(vertex); + } + } + + std::vector<int> death; + if (get<1>(pair) != stptr_->null_simplex()) { + for (auto vertex : stptr_->simplex_vertex_range(get<1>(pair))) { + death.push_back(vertex); + } + } + + persistence_pairs.push_back(std::make_pair(birth, death)); + } + return persistence_pairs; + } + private: // A copy FilteredComplex* stptr_; diff --git a/src/cython/include/Tangential_complex_interface.h b/src/cython/include/Tangential_complex_interface.h index 2772460a..71418886 100644 --- a/src/cython/include/Tangential_complex_interface.h +++ b/src/cython/include/Tangential_complex_interface.h @@ -45,24 +45,19 @@ class Tangential_complex_interface { using TC = Tangential_complex<Dynamic_kernel, CGAL::Dynamic_dimension_tag, CGAL::Parallel_tag>; public: - Tangential_complex_interface(const std::vector<std::vector<double>>& points) { + Tangential_complex_interface(int intrisic_dim, const std::vector<std::vector<double>>& points) { Dynamic_kernel k; - unsigned intrisic_dim = 0; - if (points.size() > 0) - intrisic_dim = points[0].size() - 1; tangential_complex_ = new TC(points, intrisic_dim, k); tangential_complex_->compute_tangential_complex(); num_inconsistencies_ = tangential_complex_->number_of_inconsistent_simplices(); } - Tangential_complex_interface(const std::string& off_file_name, bool from_file = true) { - Gudhi::Points_off_reader<Point_d> off_reader(off_file_name); + Tangential_complex_interface(int intrisic_dim, const std::string& off_file_name, bool from_file = true) { Dynamic_kernel k; - unsigned intrisic_dim = 0; + + Gudhi::Points_off_reader<Point_d> off_reader(off_file_name); std::vector<Point_d> points = off_reader.get_point_cloud(); - if (points.size() > 0) - intrisic_dim = points[0].size() - 1; tangential_complex_ = new TC(points, intrisic_dim, k); tangential_complex_->compute_tangential_complex(); diff --git a/src/cython/setup.py.in b/src/cython/setup.py.in index b6ca4bcb..4037aab6 100644 --- a/src/cython/setup.py.in +++ b/src/cython/setup.py.in @@ -46,4 +46,5 @@ setup( version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', ext_modules = cythonize(gudhi), + install_requires = ["cython",], ) diff --git a/src/cython/test/test_cover_complex.py b/src/cython/test/test_cover_complex.py new file mode 100755 index 00000000..58935264 --- /dev/null +++ b/src/cython/test/test_cover_complex.py @@ -0,0 +1,92 @@ +from gudhi import CoverComplex + +"""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) 2018 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) 2018 Inria" +__license__ = "GPL v3" + + +def test_empty_constructor(): + # Try to create an empty CoverComplex + cover = CoverComplex() + assert cover.__is_defined() == True + +def test_non_existing_file_read(): + # Try to open a non existing file + cover = CoverComplex() + assert (cover.read_point_cloud('pouetpouettralala.toubiloubabdou') == False) + +def test_files_creation(): + # Create test file + cloud_file = open('cloud', 'w') + cloud_file.write('nOFF\n3\n3 0 0\n0 0 0\n2 1 0\n4 0 0') + cloud_file.close() + cover_file = open('cover', 'w') + cover_file.write('1\n2\n3') + cover_file.close() + graph_file = open('graph', 'w') + graph_file.write('0 1\n0 2\n1 2') + graph_file.close() + +def test_nerve(): + nerve = CoverComplex() + nerve.set_type('Nerve') + assert (nerve.read_point_cloud('cloud') == True) + nerve.set_color_from_coordinate() + nerve.set_graph_from_file('graph') + nerve.set_cover_from_file('cover') + nerve.find_simplices() + stree = nerve.create_simplex_tree() + + assert (stree.num_vertices() == 3) + assert ((stree.num_simplices() - stree.num_vertices()) == 0) + assert (stree.dimension() == 0) + +def test_graph_induced_complex(): + gic = CoverComplex() + gic.set_type('GIC') + assert (gic.read_point_cloud('cloud') == True) + gic.set_color_from_coordinate() + gic.set_graph_from_file('graph') + gic.set_cover_from_file('cover') + gic.find_simplices() + stree = gic.create_simplex_tree() + + assert (stree.num_vertices() == 3) + assert ((stree.num_simplices() - stree.num_vertices()) == 4) + assert (stree.dimension() == 2) + +def test_voronoi_graph_induced_complex(): + gic = CoverComplex() + gic.set_type('GIC') + assert (gic.read_point_cloud('cloud') == True) + gic.set_color_from_coordinate() + gic.set_graph_from_file('graph') + gic.set_cover_from_Voronoi(2) + gic.find_simplices() + stree = gic.create_simplex_tree() + + assert (stree.num_vertices() == 2) + assert ((stree.num_simplices() - stree.num_vertices()) == 1) + assert (stree.dimension() == 1) diff --git a/src/cython/test/test_cubical_complex.py b/src/cython/test/test_cubical_complex.py index 79d39aa8..92e591e9 100755 --- a/src/cython/test/test_cubical_complex.py +++ b/src/cython/test/test_cubical_complex.py @@ -72,6 +72,17 @@ def test_dimension_simple_constructor(): assert cub.betti_numbers() == [1, 0, 0] assert cub.persistent_betti_numbers(0, 1000) == [0, 0, 0] +def test_user_case_simple_constructor(): + cub = CubicalComplex(dimensions=[3, 3], + top_dimensional_cells = [float('inf'), 0.,0.,0.,1.,0.,0.,0.,0.]) + assert cub.__is_defined() == True + assert cub.__is_persistence_defined() == False + assert cub.persistence() == [(1, (0.0, 1.0)), (0, (0.0, float('inf')))] + assert cub.__is_persistence_defined() == True + other_cub = CubicalComplex(dimensions=[3, 3], + top_dimensional_cells = [1000., 0.,0.,0.,1.,0.,0.,0.,0.]) + assert other_cub.persistence() == [(1, (0.0, 1.0)), (0, (0.0, float('inf')))] + def test_dimension_file_constructor(): # Create test file test_file = open('CubicalOneSphere.txt', 'w') diff --git a/src/cython/test/test_simplex_tree.py b/src/cython/test/test_simplex_tree.py index 029e7729..cb701c9a 100755 --- a/src/cython/test/test_simplex_tree.py +++ b/src/cython/test/test_simplex_tree.py @@ -161,3 +161,47 @@ def test_automatic_dimension(): assert st.upper_bound_dimension() == 2 assert st.dimension() == 1 assert st.upper_bound_dimension() == 1 + +def test_make_filtration_non_decreasing(): + st = SimplexTree() + assert st.__is_defined() == True + assert st.__is_persistence_defined() == False + + # Inserted simplex: + # 1 + # o + # /X\ + # o---o---o---o + # 2 0 3\X/4 + # o + # 5 + assert st.insert([2, 1, 0], filtration=2.0) == True + assert st.insert([3, 0], filtration=2.0) == True + assert st.insert([3, 4, 5], filtration=2.0) == True + + assert st.make_filtration_non_decreasing() == False + + # Because of non decreasing property of simplex tree, { 0 } , { 1 } and + # { 0, 1 } are going to be set from value 2.0 to 1.0 + st.insert([0, 1, 6, 7], filtration=1.0); + + assert st.make_filtration_non_decreasing() == False + + # Modify specific values to test make_filtration_non_decreasing + st.assign_filtration([0,1,6,7], 0.8); + st.assign_filtration([0,1,6], 0.9); + st.assign_filtration([0,6], 0.6); + st.assign_filtration([3,4,5], 1.2); + st.assign_filtration([3,4], 1.1); + st.assign_filtration([4,5], 1.99); + + assert st.make_filtration_non_decreasing() == True + + assert st.filtration([0,1,6,7]) == 1. + assert st.filtration([0,1,6]) == 1. + assert st.filtration([0,1]) == 1. + assert st.filtration([0]) == 1. + assert st.filtration([1]) == 1. + assert st.filtration([3,4,5]) == 2. + assert st.filtration([3,4]) == 2. + assert st.filtration([4,5]) == 2. diff --git a/src/cython/test/test_tangential_complex.py b/src/cython/test/test_tangential_complex.py index fe623c7b..5385a0d3 100755 --- a/src/cython/test/test_tangential_complex.py +++ b/src/cython/test/test_tangential_complex.py @@ -29,7 +29,7 @@ __license__ = "GPL v3" def test_tangential(): point_list = [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]] - tc = TangentialComplex(points=point_list) + tc = TangentialComplex(intrisic_dim = 1, points=point_list) assert tc.__is_defined() == True assert tc.num_vertices() == 4 |