diff options
Diffstat (limited to 'src/cython')
111 files changed, 2891 insertions, 862 deletions
diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index afca9d60..dc2e9278 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -1,4 +1,3 @@ -cmake_minimum_required(VERSION 2.8) project(Cython) function( add_gudhi_cython_lib THE_LIB ) @@ -17,298 +16,429 @@ 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(PYTHONINTERP_FOUND) + if(CYTHON_FOUND) + 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(SCIPY_FOUND) + add_gudhi_debug_info("Scipy version ${SCIPY_VERSION}") + endif() + if(MATPLOTLIB_FOUND AND NUMPY_FOUND AND SCIPY_FOUND) + set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") + else() + set(GUDHI_CYTHON_MISSING_MODULES "${GUDHI_CYTHON_MODULES}persistence_graphical_tools;") + endif() -if(CYTHON_FOUND) - message("++ ${PYTHON_EXECUTABLE} v.${PYTHON_VERSION_STRING} - Cython is ${CYTHON_EXECUTABLE} - 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', ") - - # 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) - - 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() - - # Gudhi and CGAL compilation option - if(MSVC) - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'/fp:strict', ") - else(MSVC) - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-std=c++11', ") - endif(MSVC) - if(CMAKE_COMPILER_IS_GNUCXX) - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-frounding-math', ") - endif(CMAKE_COMPILER_IS_GNUCXX) - if (CMAKE_CXX_COMPILER_ID MATCHES Intel) - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-fp-model strict', ") - endif(CMAKE_CXX_COMPILER_ID MATCHES Intel) - if (DEBUG_TRACES) - # For programs to be more verbose - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DDEBUG_TRACES', ") - 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', ") + + # Gudhi and CGAL compilation option + if(MSVC) + set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'/fp:strict', ") + else(MSVC) + set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-std=c++11', ") + endif(MSVC) + if(CMAKE_COMPILER_IS_GNUCXX) + set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-frounding-math', ") + endif(CMAKE_COMPILER_IS_GNUCXX) + if (CMAKE_CXX_COMPILER_ID MATCHES Intel) + set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-fp-model strict', ") + endif(CMAKE_CXX_COMPILER_ID MATCHES Intel) + if (DEBUG_TRACES) + # For programs to be more verbose + set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DDEBUG_TRACES', ") + endif() - if (EIGEN3_FOUND) - # 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) - 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_TANGENTIAL_COMPLEX "include '${CMAKE_CURRENT_SOURCE_DIR}/cython/tangential_complex.pyx'") - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) - 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) - 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) - - if(CGAL_FOUND) - # Add CGAL compilation args - if(CGAL_HEADER_ONLY) - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_HEADER_ONLY', ") - else(CGAL_HEADER_ONLY) - add_gudhi_cython_lib(${CGAL_LIBRARIES}) - 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}) - set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ") - endif(CGAL_HEADER_ONLY) - # GMP and GMPXX are not required, but if present, CGAL will link with them. - if(GMP_FOUND) - 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) - 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}', ") - endif(GMPXX_FOUND) - endif(GMP_FOUND) - endif(CGAL_FOUND) - - # Specific for Mac - if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-mmacosx-version-min=10.12', ") - set(GUDHI_CYTHON_EXTRA_LINK_ARGS "${GUDHI_CYTHON_EXTRA_LINK_ARGS}'-mmacosx-version-min=10.12', ") - endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - - # Loop on INCLUDE_DIRECTORIES PROPERTY - get_property(GUDHI_INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) - foreach(GUDHI_INCLUDE_DIRECTORY ${GUDHI_INCLUDE_DIRECTORIES}) - set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${GUDHI_INCLUDE_DIRECTORY}', ") - endforeach() - set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${CMAKE_SOURCE_DIR}/${GUDHI_CYTHON_PATH}/include', ") - - if (TBB_FOUND) - 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}) - set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${TBB_LIBRARY_DIRS}', ") - set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${TBB_INCLUDE_DIRS}', ") - 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'") + 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'") + 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'") + 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") + 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(UNIX) - set( GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}") - endif(UNIX) - - # Generate setup.py file to cythonize Gudhi - This file must be named setup.py by convention - configure_file(setup.py.in "${CMAKE_CURRENT_BINARY_DIR}/setup.py" @ONLY) - # Generate gudhi.pyx - Gudhi cython file - configure_file(gudhi.pyx.in "${CMAKE_CURRENT_BINARY_DIR}/gudhi.pyx" @ONLY) - - add_custom_command( - OUTPUT gudhi.so - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/setup.py" "build_ext" "--inplace") - - add_custom_target(cython ALL DEPENDS gudhi.so - COMMENT "Do not forget to add ${CMAKE_CURRENT_BINARY_DIR}/ to your PYTHONPATH before using examples or tests") - - # For installation purpose - # TODO(VR) : files matching pattern mechanism is copying all cython directory - install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" DESTINATION "${PYTHON_SITE_PACKAGES}/" FILES_MATCHING - PATTERN "*.so" - PATTERN "*.dylib" - PATTERN "*.pyd") - - # Test examples - if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) - # Bottleneck and Alpha - add_test(NAME alpha_rips_persistence_bottleneck_distance_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_rips_persistence_bottleneck_distance.py" - -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -t 0.15 -d 3) + if(CGAL_FOUND) + can_cgal_use_cxx11_thread_local() + if (NOT CGAL_CAN_USE_CXX11_THREAD_LOCAL_RESULT) + if(CMAKE_BUILD_TYPE MATCHES Debug) + add_gudhi_cython_lib("${Boost_THREAD_LIBRARY_DEBUG}") + else() + add_gudhi_cython_lib("${Boost_THREAD_LIBRARY_RELEASE}") + endif() + 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_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, + if(CMAKE_BUILD_TYPE MATCHES Debug) + add_gudhi_cython_lib("${Boost_SYSTEM_LIBRARY_DEBUG}") + else() + add_gudhi_cython_lib("${Boost_SYSTEM_LIBRARY_RELEASE}") + endif() + set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${Boost_LIBRARY_DIRS}', ") + 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}', ") + endif(GMPXX_FOUND) + endif(GMP_FOUND) + endif(CGAL_FOUND) + + # Specific for Mac + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(GUDHI_CYTHON_EXTRA_COMPILE_ARGS "${GUDHI_CYTHON_EXTRA_COMPILE_ARGS}'-mmacosx-version-min=10.12', ") + set(GUDHI_CYTHON_EXTRA_LINK_ARGS "${GUDHI_CYTHON_EXTRA_LINK_ARGS}'-mmacosx-version-min=10.12', ") + endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + + # Loop on INCLUDE_DIRECTORIES PROPERTY + get_property(GUDHI_INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) + foreach(GUDHI_INCLUDE_DIRECTORY ${GUDHI_INCLUDE_DIRECTORIES}) + set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${GUDHI_INCLUDE_DIRECTORY}', ") + endforeach() + 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', ") + if(CMAKE_BUILD_TYPE MATCHES Debug) + add_gudhi_cython_lib("${TBB_DEBUG_LIBRARY}") + add_gudhi_cython_lib("${TBB_MALLOC_DEBUG_LIBRARY}") + else() + add_gudhi_cython_lib("${TBB_RELEASE_LIBRARY}") + add_gudhi_cython_lib("${TBB_MALLOC_RELEASE_LIBRARY}") + endif() + set(GUDHI_CYTHON_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}'${TBB_LIBRARY_DIRS}', ") + set(GUDHI_CYTHON_INCLUDE_DIRS "${GUDHI_CYTHON_INCLUDE_DIRS}'${TBB_INCLUDE_DIRS}', ") + endif() - # Tangential - add_test(NAME tangential_complex_plain_homology_from_off_file_example_py_test + if(UNIX) + set( GUDHI_CYTHON_RUNTIME_LIBRARY_DIRS "${GUDHI_CYTHON_LIBRARY_DIRS}") + endif(UNIX) + + # Generate setup.py file to cythonize Gudhi - This file must be named setup.py by convention + configure_file(setup.py.in "${CMAKE_CURRENT_BINARY_DIR}/setup.py" @ONLY) + # Generate gudhi.pyx - Gudhi cython file + configure_file(gudhi.pyx.in "${CMAKE_CURRENT_BINARY_DIR}/gudhi.pyx" @ONLY) + + add_custom_command( + OUTPUT gudhi.so + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/setup.py" "build_ext" "--inplace") + + add_custom_target(cython ALL DEPENDS gudhi.so + COMMENT "Do not forget to add ${CMAKE_CURRENT_BINARY_DIR}/ to your PYTHONPATH before using examples or tests") + + # For installation purpose + # TODO(VR) : files matching pattern mechanism is copying all cython directory + install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" DESTINATION "${PYTHON_SITE_PACKAGES}/" FILES_MATCHING + PATTERN "*.so" + PATTERN "*.dylib" + PATTERN "*.pyd") + + # Test examples + if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + # Bottleneck and Alpha + add_test(NAME alpha_rips_persistence_bottleneck_distance_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_rips_persistence_bottleneck_distance.py" + -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off -t 0.15 -d 3) + + 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/bottleneck_basic_example.py") + + add_gudhi_py_test(test_bottleneck_distance) + + # 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/nerve_of_a_covering.py" + -f human.off -c 2 -r 10 -g 0.3) + + 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/coordinate_graph_induced_complex.py" + -f human.off -c 0 -v) + + 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) + + 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/voronoi_graph_induced_complex.py" + -f human.off -n 700 -v) + + 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) + # Alpha + add_test(NAME alpha_complex_from_points_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_from_points_example.py") + + 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) + + endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) + + if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) + # Euclidean witness + add_gudhi_py_test(test_euclidean_witness_complex) + + endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) + + # Cubical + add_test(NAME periodic_cubical_complex_barcode_persistence_from_perseus_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 -f ${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off) - - add_gudhi_py_test(test_tangential_complex) + ${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) + + 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() - # 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_gudhi_py_test(test_cubical_complex) + + # Rips + 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 euclidean_witness_complex_diagram_persistence_from_off_file_example_py_test + add_test(NAME rips_complex_from_points_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/rips_complex_from_points_example.py) - # Subsampling - add_gudhi_py_test(test_subsampling) + add_gudhi_py_test(test_rips_complex) - 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 + # Simplex tree + add_test(NAME simplex_tree_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/simplex_tree_example.py) - add_gudhi_py_test(test_bottleneck_distance) - endif (NOT CGAL_VERSION VERSION_LESS 4.8.1) + add_gudhi_py_test(test_simplex_tree) - if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) - # Alpha - add_test(NAME alpha_complex_from_points_example_py_test + # Witness + add_test(NAME witness_complex_from_nearest_landmark_table_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_from_points_example.py") - - 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) - - add_gudhi_py_test(test_alpha_complex) - - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0) - - if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) - # Euclidean witness - add_gudhi_py_test(test_euclidean_witness_complex) - - endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0) - - # Cubical - add_test(NAME periodic_cubical_complex_barcode_persistence_from_perseus_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/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) - - 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) - - add_test(NAME rips_complex_from_points_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_from_points_example.py) - - add_gudhi_py_test(test_rips_complex) - - # Simplex tree - add_test(NAME simplex_tree_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/simplex_tree_example.py) - - add_gudhi_py_test(test_simplex_tree) - - # Witness - add_test(NAME witness_complex_from_nearest_landmark_table_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/witness_complex_from_nearest_landmark_table.py) - - add_gudhi_py_test(test_witness_complex) - - # Reader utils - 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) - 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 - if (GUDHI_CYTHON_PATH STREQUAL "src/cython") - set (GUDHI_SPHINX_MESSAGE "${GUDHI_SPHINX_MESSAGE} \n WARNING : Sphinx is configured for user version, you run it on developper version. Images and biblio will miss") - endif() - # sphinx target requires gudhi.so, because conf.py reads gudhi version from it - add_custom_target(sphinx - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc - COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" - ${SPHINX_PATH} -b html ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/sphinx - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/gudhi.so" - COMMENT "${GUDHI_SPHINX_MESSAGE}" VERBATIM) - - add_test(NAME sphinx_py_test - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - 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(CYTHON_FOUND) + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/witness_complex_from_nearest_landmark_table.py) + + add_gudhi_py_test(test_witness_complex) + + # Reader utils + add_gudhi_py_test(test_reader_utils) + + # Documentation generation is available through sphinx - requires all modules + if(SPHINX_PATH) + if(MATPLOTLIB_FOUND) + if(NUMPY_FOUND) + if(SCIPY_FOUND) + if(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 + if (GUDHI_CYTHON_PATH STREQUAL "src/cython") + set (GUDHI_SPHINX_MESSAGE "${GUDHI_SPHINX_MESSAGE} \n WARNING : Sphinx is configured for user version, you run it on developper version. Images and biblio will miss") + endif() + # sphinx target requires gudhi.so, because conf.py reads gudhi version from it + add_custom_target(sphinx + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc + COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" + ${SPHINX_PATH} -b html ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/sphinx + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/gudhi.so" + COMMENT "${GUDHI_SPHINX_MESSAGE}" VERBATIM) + + add_test(NAME sphinx_py_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}" + ${SPHINX_PATH} -b doctest ${CMAKE_CURRENT_SOURCE_DIR}/doc ${CMAKE_CURRENT_BINARY_DIR}/doctest) + + # Set missing or not modules + set(GUDHI_MODULES ${GUDHI_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MODULES") + else(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + message("++ Python documentation module will not be compiled because it requires a CGAL with Eigen3 version greater or equal than 4.8.1") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.8.1) + else(SCIPY_FOUND) + message("++ Python documentation module will not be compiled because scipy was not found") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(SCIPY_FOUND) + else(NUMPY_FOUND) + message("++ Python documentation module will not be compiled because numpy was not found") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(NUMPY_FOUND) + else(MATPLOTLIB_FOUND) + message("++ Python documentation module will not be compiled because matplotlib was not found") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(MATPLOTLIB_FOUND) + else(SPHINX_PATH) + message("++ Python documentation module will not be compiled because sphinx and sphinxcontrib-bibtex were not found") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(SPHINX_PATH) + + + # Set missing or not modules + set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") + else(CYTHON_FOUND) + message("++ Python module will not be compiled because cython was not found") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(CYTHON_FOUND) +else(PYTHONINTERP_FOUND) + message("++ Python module will not be compiled because no Python interpreter was found") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python" CACHE INTERNAL "GUDHI_MISSING_MODULES") +endif(PYTHONINTERP_FOUND) diff --git a/src/cython/cython/alpha_complex.pyx b/src/cython/cython/alpha_complex.pyx index a0e8f9b7..4f772e31 100644 --- a/src/cython/cython/alpha_complex.pyx +++ b/src/cython/cython/alpha_complex.pyx @@ -11,7 +11,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -28,7 +28,7 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Alpha_complex_interface.h" namespace "Gudhi": diff --git a/src/cython/cython/bottleneck_distance.pyx b/src/cython/cython/bottleneck_distance.pyx index 9fb377ff..76ef81f4 100644 --- a/src/cython/cython/bottleneck_distance.pyx +++ b/src/cython/cython/bottleneck_distance.pyx @@ -9,7 +9,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Bottleneck_distance_interface.h" namespace "Gudhi::persistence_diagram": diff --git a/src/cython/cython/cubical_complex.pyx b/src/cython/cython/cubical_complex.pyx index ffc85130..e94cd539 100644 --- a/src/cython/cython/cubical_complex.pyx +++ b/src/cython/cython/cubical_complex.pyx @@ -11,7 +11,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -28,7 +28,7 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Cubical_complex_interface.h" namespace "Gudhi": @@ -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/euclidean_strong_witness_complex.pyx b/src/cython/cython/euclidean_strong_witness_complex.pyx index c1523892..62b7cf71 100644 --- a/src/cython/cython/euclidean_strong_witness_complex.pyx +++ b/src/cython/cython/euclidean_strong_witness_complex.pyx @@ -8,7 +8,7 @@ from libcpp.utility cimport pair Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ from libcpp.utility cimport pair """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Euclidean_strong_witness_complex_interface.h" namespace "Gudhi": diff --git a/src/cython/cython/euclidean_witness_complex.pyx b/src/cython/cython/euclidean_witness_complex.pyx index 7c443b6b..c10ca73d 100644 --- a/src/cython/cython/euclidean_witness_complex.pyx +++ b/src/cython/cython/euclidean_witness_complex.pyx @@ -8,7 +8,7 @@ from libcpp.utility cimport pair Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ from libcpp.utility cimport pair """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Euclidean_witness_complex_interface.h" namespace "Gudhi": diff --git a/src/cython/cython/nerve_gic.pyx b/src/cython/cython/nerve_gic.pyx new file mode 100644 index 00000000..5f01b379 --- /dev/null +++ b/src/cython/cython/nerve_gic.pyx @@ -0,0 +1,419 @@ +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) + void set_distances_from_range(vector[vector[double]] distance_matrix) + +# 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 set_distances_from_range(self, distance_matrix): + """ Reads and stores the input distance matrix from a vector stored in memory. + + :param distance_matrix: Input vector containing the distance matrix. + :type distance_matrix: vector[vector[double]] + """ + return self.thisptr.set_distances_from_range(distance_matrix) + + 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/off_reader.pyx b/src/cython/cython/off_reader.pyx index b6e107ef..b939013f 100644 --- a/src/cython/cython/off_reader.pyx +++ b/src/cython/cython/off_reader.pyx @@ -9,7 +9,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Off_reader_interface.h" namespace "Gudhi": @@ -46,4 +46,5 @@ def read_off(off_file=''): return read_points_from_OFF_file(str.encode(off_file)) else: print("file " + off_file + " not found.") + return [] diff --git a/src/cython/cython/periodic_cubical_complex.pyx b/src/cython/cython/periodic_cubical_complex.pyx index 581c7b69..e626950b 100644 --- a/src/cython/cython/periodic_cubical_complex.pyx +++ b/src/cython/cython/periodic_cubical_complex.pyx @@ -11,7 +11,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -28,12 +28,12 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Cubical_complex_interface.h" namespace "Gudhi": cdef cppclass Periodic_cubical_complex_base_interface "Gudhi::Cubical_complex::Cubical_complex_interface<Gudhi::cubical_complex::Bitmap_cubical_complex_periodic_boundary_conditions_base<double>>": - Periodic_cubical_complex_base_interface(vector[unsigned] dimensions, vector[double] top_dimensional_cells) + Periodic_cubical_complex_base_interface(vector[unsigned] dimensions, vector[double] top_dimensional_cells, vector[bool] periodic_dimensions) Periodic_cubical_complex_base_interface(string perseus_file) int num_simplices() int dimension() @@ -58,7 +58,7 @@ cdef class PeriodicCubicalComplex: # Fake constructor that does nothing but documenting the constructor def __init__(self, dimensions=None, top_dimensional_cells=None, - perseus_file=''): + periodic_dimensions=None, perseus_file=''): """PeriodicCubicalComplex constructor from dimensions and top_dimensional_cells or from a Perseus-style file name. @@ -66,6 +66,8 @@ cdef class PeriodicCubicalComplex: :type dimensions: list of int :param top_dimensional_cells: A list of cells filtration values. :type top_dimensional_cells: list of double + :param periodic_dimensions: A list of top dimensional cells periodicity value. + :type periodic_dimensions: list of boolean Or @@ -75,10 +77,10 @@ cdef class PeriodicCubicalComplex: # The real cython constructor def __cinit__(self, dimensions=None, top_dimensional_cells=None, - perseus_file=''): - if (dimensions is not None) and (top_dimensional_cells is not None) and (perseus_file is ''): - self.thisptr = new Periodic_cubical_complex_base_interface(dimensions, top_dimensional_cells) - elif (dimensions is None) and (top_dimensional_cells is None) and (perseus_file is not ''): + periodic_dimensions=None, perseus_file=''): + if (dimensions is not None) and (top_dimensional_cells is not None) and (periodic_dimensions is not None) and (perseus_file is ''): + self.thisptr = new Periodic_cubical_complex_base_interface(dimensions, top_dimensional_cells, periodic_dimensions) + elif (dimensions is None) and (top_dimensional_cells is None) and (periodic_dimensions is None) and (perseus_file is not ''): if os.path.isfile(perseus_file): self.thisptr = new Periodic_cubical_complex_base_interface(str.encode(perseus_file)) else: @@ -104,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 @@ -130,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 @@ -142,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: @@ -155,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). @@ -177,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 fb837e29..d7be936f 100755..100644 --- a/src/cython/cython/persistence_graphical_tools.py +++ b/src/cython/cython/persistence_graphical_tools.py @@ -1,14 +1,10 @@ -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. Author(s): Vincent Rouvreau, Bertrand Michel - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,16 +21,16 @@ import os """ __author__ = "Vincent Rouvreau, Bertrand Michel" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" -def __min_birth_max_death(persistence, band_boot=0.): +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_boot: bootstrap band - :type band_boot: float. + :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 @@ -48,8 +44,8 @@ def __min_birth_max_death(persistence, band_boot=0.): 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 + if band > 0.: + max_death += band return (min_birth, max_death) """ @@ -58,145 +54,295 @@ 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). +def plot_persistence_barcode(persistence=[], persistence_file='', alpha=0.6, + max_intervals=1000, 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 intervals values list grouped by dimension. + :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. - :returns: plot the dimension palette values. + :param max_intervals: maximal number of intervals to display. + Selected intervals are those with the longest life time. Set it + to 0 to see all. Default value is 1000. + :type max_intervals: int. + :param inf_delta: Infinity is placed at :code:`((max_death - min_birth) x + inf_delta)` above :code:`max_death` value. A reasonable value is + between 0.05 and 0.5 - default is 0.1. + :type inf_delta: float. + :param legend: Display the dimension color legend (default is False). + :type legend: boolean. + :returns: A matplotlib object containing horizontal bar plot of persistence + (launch `show()` method on it to display it). """ - colors = [] - for color in palette: - colors.append(color) + try: + import matplotlib.pyplot as plt + import matplotlib.patches as mpatches + import numpy as np + import os - y_pos = np.arange(len(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 - plt.barh(y_pos, y_pos + 1, align='center', alpha=alpha, color=colors) - plt.ylabel('Dimension') - plt.title('Dimension palette values') - return plt + if max_barcodes is not 1000: + print('Deprecated parameter. It has been replaced by max_intervals') + max_intervals = max_barcodes -def plot_persistence_barcode(persistence=[], persistence_file='', alpha=0.6, max_barcodes=0): - """This function plots the persistence bar code. + if max_intervals > 0 and max_intervals < len(persistence): + # Sort by life time, then takes only the max_intervals elements + persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_intervals] - :param persistence: The persistence to plot. + 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 + + except ImportError: + print("This function is not available, you may be missing numpy and/or matplotlib.") + +def plot_persistence_diagram(persistence=[], persistence_file='', alpha=0.6, + band=0., max_intervals=1000, 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 intervals values list grouped by dimension. :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A persistence file style name (reset persistence if both are set). + :param persistence_file: A :doc:`persistence file <fileformats>` 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). + :param alpha: plot 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 - (persistence will be sorted by life time if max_barcodes is set) - :type max_barcodes: int. - :returns: plot -- An horizontal bar plot of persistence. + :param band: band (not displayed if :math:`\leq` 0. - default is 0.) + :type band: float. + :param max_intervals: maximal number of intervals to display. + Selected intervals are those with the longest life time. Set it + to 0 to see all. Default value is 1000. + :type max_intervals: int. + :param inf_delta: Infinity is placed at :code:`((max_death - min_birth) x + inf_delta)` above :code:`max_death` value. A reasonable value is + between 0.05 and 0.5 - default is 0.1. + :type inf_delta: float. + :param legend: Display the dimension color legend (default is False). + :type legend: boolean. + :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_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 + try: + import matplotlib.pyplot as plt + import matplotlib.patches as mpatches + import numpy as np + import os - 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 + 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 -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. + if max_plots is not 1000: + print('Deprecated parameter. It has been replaced by max_intervals') + max_intervals = max_plots - :param persistence: The persistence to plot. + if max_intervals > 0 and max_intervals < len(persistence): + # Sort by life time, then takes only the max_intervals elements + persistence = sorted(persistence, key=lambda life_time: life_time[1][1]-life_time[1][0], reverse=True)[:max_intervals] + + (min_birth, max_death) = __min_birth_max_death(persistence, band) + 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]]) + + 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: + print("This function is not available, you may be missing numpy and/or matplotlib.") + +def plot_persistence_density(persistence=[], persistence_file='', + nbins=300, bw_method=None, + max_intervals=1000, dimension=None, + cmap=None, legend=False): + """This function plots the persistence density from persistence + values list or from a :doc:`persistence file <fileformats>`. Be + aware that this function does not distinguish the dimension, it is + up to you to select the required one. This function also does not handle + degenerate data set (scipy correlation matrix inversion can fail). + + :param persistence: Persistence intervals values list grouped by dimension. :type persistence: list of tuples(dimension, tuple(birth, death)). - :param persistence_file: A persistence file style name (reset persistence if both are set). + :param persistence_file: A :doc:`persistence file <fileformats>` + 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. + :param nbins: Evaluate a gaussian kde on a regular grid of nbins x + nbins over data extents (default is 300) + :type nbins: int. + :param bw_method: The method used to calculate the estimator + bandwidth. This can be 'scott', 'silverman', a scalar constant + or a callable. If a scalar, this will be used directly as + kde.factor. If a callable, it should take a gaussian_kde + instance as only parameter and return a scalar. If None + (default), 'scott' is used. See + `scipy.stats.gaussian_kde documentation + <http://scipy.github.io/devdocs/generated/scipy.stats.gaussian_kde.html>`_ + for more details. + :type bw_method: str, scalar or callable, optional. + :param max_intervals: maximal number of points used in the density + estimation. + Selected intervals are those with the longest life time. Set it + to 0 to see all. Default value is 1000. + :type max_intervals: int. + :param dimension: the dimension to be selected in the intervals + (default is None to mix all dimensions). + :type dimension: int. + :param cmap: A matplotlib colormap (default is + matplotlib.pyplot.cm.hot_r). + :type cmap: cf. matplotlib colormap. + :param legend: Display the color bar values (default is False). + :type legend: boolean. + :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_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]]) + try: + import matplotlib.pyplot as plt + import numpy as np + from scipy.stats import kde + import os + import math + + 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 + + persistence_dim = [] + if dimension is not None: + persistence_dim = [(dim_interval) for dim_interval in persistence if (dim_interval[0] == dimension)] 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 + persistence_dim = persistence + + if max_intervals > 0 and max_intervals < len(persistence_dim): + # Sort by life time, then takes only the max_intervals elements + persistence_dim = sorted(persistence_dim, + key=lambda life_time: life_time[1][1]-life_time[1][0], + reverse=True)[:max_intervals] + + # Set as numpy array birth and death (remove undefined values - inf and NaN) + birth = np.asarray([(interval[1][0]) for interval in persistence_dim if (math.isfinite(interval[1][1]) and math.isfinite(interval[1][0]))]) + death = np.asarray([(interval[1][1]) for interval in persistence_dim if (math.isfinite(interval[1][1]) and math.isfinite(interval[1][0]))]) + + # line display of equation : birth = death + x = np.linspace(death.min(), birth.max(), 1000) + plt.plot(x, x, color='k', linewidth=1.0) + + # Evaluate a gaussian kde on a regular grid of nbins x nbins over data extents + k = kde.gaussian_kde([birth,death], bw_method=bw_method) + xi, yi = np.mgrid[birth.min():birth.max():nbins*1j, death.min():death.max():nbins*1j] + zi = k(np.vstack([xi.flatten(), yi.flatten()])) + + # default cmap value cannot be done at argument definition level as matplotlib is not yet defined. + if cmap is None: + cmap = plt.cm.hot_r + # Make the plot + plt.pcolormesh(xi, yi, zi.reshape(xi.shape), cmap=cmap) + + if legend: + plt.colorbar() + + plt.title('Persistence density') + plt.xlabel('Birth') + plt.ylabel('Death') + return plt + + except ImportError: + print("This function is not available, you may be missing numpy, matplotlib and/or scipy.") diff --git a/src/cython/cython/reader_utils.pyx b/src/cython/cython/reader_utils.pyx index 3a17c5a0..e4572db0 100644 --- a/src/cython/cython/reader_utils.pyx +++ b/src/cython/cython/reader_utils.pyx @@ -11,7 +11,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2017 INRIA + Copyright (C) 2017 Inria This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2017 INRIA" +__copyright__ = "Copyright (C) 2017 Inria" __license__ = "GPL v3" cdef extern from "Reader_utils_interface.h" namespace "Gudhi": diff --git a/src/cython/cython/rips_complex.pyx b/src/cython/cython/rips_complex.pyx index ad9b0a4d..30ca4443 100644 --- a/src/cython/cython/rips_complex.pyx +++ b/src/cython/cython/rips_complex.pyx @@ -11,7 +11,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -28,14 +28,12 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Rips_complex_interface.h" namespace "Gudhi": cdef cppclass Rips_complex_interface "Gudhi::rips_complex::Rips_complex_interface": Rips_complex_interface(vector[vector[double]] values, double threshold, bool euclidean) - # bool from_file is a workaround for cython to find the correct signature - Rips_complex_interface(string file_name, double threshold, bool euclidean, bool from_file) void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, int dim_max) # RipsComplex python interface @@ -49,52 +47,25 @@ cdef class RipsComplex: cdef Rips_complex_interface * thisptr # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=None, off_file='', distance_matrix=None, csv_file='', max_edge_length=float('inf')): + def __init__(self, points=None, distance_matrix=None, max_edge_length=float('inf')): """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 Or - :param off_file: An OFF file style name. - :type off_file: string - - Or - :param distance_matrix: A distance matrix (full square or lower triangular). :type points: list of list of double - - Or - - :param csv_file: A csv file style name containing a full square or a - lower triangular distance matrix. - :type csv_file: string """ # The real cython constructor - def __cinit__(self, points=None, off_file='', distance_matrix=None, csv_file='', max_edge_length=float('inf')): - if off_file is not '': - if os.path.isfile(off_file): - self.thisptr = new Rips_complex_interface(str.encode(off_file), - max_edge_length, - True, - True) - else: - print("file " + off_file + " not found.") - elif csv_file is not '': - if os.path.isfile(csv_file): - self.thisptr = new Rips_complex_interface(str.encode(csv_file), - max_edge_length, - False, - True) - else: - print("file " + csv_file + " not found.") - elif distance_matrix is not None: + def __cinit__(self, points=None, distance_matrix=None, max_edge_length=float('inf')): + if distance_matrix is not None: self.thisptr = new Rips_complex_interface(distance_matrix, max_edge_length, False) else: if points is None: diff --git a/src/cython/cython/simplex_tree.pyx b/src/cython/cython/simplex_tree.pyx index 45487158..8397d9d9 100644 --- a/src/cython/cython/simplex_tree.pyx +++ b/src/cython/cython/simplex_tree.pyx @@ -10,7 +10,7 @@ from libcpp.string cimport string Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -27,7 +27,7 @@ from libcpp.string cimport string """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": @@ -37,11 +37,13 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": cdef cppclass Simplex_tree_interface_full_featured "Gudhi::Simplex_tree_interface<Gudhi::Simplex_tree_options_full_featured>": Simplex_tree() double simplex_filtration(vector[int] simplex) + void assign_simplex_filtration(vector[int] simplex, double filtration) void initialize_filtration() int num_vertices() int num_simplices() void set_dimension(int dimension) int dimension() + int upper_bound_dimension() bint find_simplex(vector[int] simplex) bint insert_simplex_and_subfaces(vector[int] simplex, double filtration) @@ -50,8 +52,10 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": vector[pair[vector[int], double]] get_star(vector[int] simplex) vector[pair[vector[int], double]] get_cofaces(vector[int] simplex, int dimension) - void remove_maximal_simplex(vector[int] simplex) 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>>": @@ -61,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: @@ -103,8 +108,8 @@ cdef class SimplexTree: return self.pcohptr != NULL def filtration(self, simplex): - """This function returns the simplicial complex filtration value for a - given N-simplex. + """This function returns the filtration value for a given N-simplex in + this simplicial complex, or +infinity if it is not in the complex. :param simplex: The N-simplex, represented by a list of vertex. :type simplex: list of int. @@ -113,15 +118,31 @@ cdef class SimplexTree: """ return self.thisptr.simplex_filtration(simplex) + def assign_filtration(self, simplex, filtration): + """This function assigns the simplicial complex filtration value for a + given N-simplex. + + :param simplex: The N-simplex, represented by a list of vertex. + :type simplex: list of int. + :param filtration: The simplicial complex filtration value. + :type filtration: float + """ + self.thisptr.assign_simplex_filtration(simplex, filtration) + def initialize_filtration(self): """This function initializes and sorts the simplicial complex filtration vector. .. note:: - This function must be launched before persistence, betti_numbers, - persistent_betti_numbers or get_filtration after inserting or - removing simplices. + This function must be launched before + :func:`persistence()<gudhi.SimplexTree.persistence>`, + :func:`betti_numbers()<gudhi.SimplexTree.betti_numbers>`, + :func:`persistent_betti_numbers()<gudhi.SimplexTree.persistent_betti_numbers>`, + or :func:`get_filtration()<gudhi.SimplexTree.get_filtration>` + after :func:`inserting<gudhi.SimplexTree.insert>` or + :func:`removing<gudhi.SimplexTree.remove_maximal_simplex>` + simplices. """ self.thisptr.initialize_filtration() @@ -148,21 +169,42 @@ cdef class SimplexTree: :returns: the simplicial complex dimension. :rtype: int + + .. note:: + + This function is not constant time because it can recompute + dimension if required (can be triggered by + :func:`remove_maximal_simplex()<gudhi.SimplexTree.remove_maximal_simplex>` + or + :func:`prune_above_filtration()<gudhi.SimplexTree.prune_above_filtration>` + methods). """ return self.thisptr.dimension() - def set_dimension(self, dimension): - """This function sets the dimension of the simplicial complex. + def upper_bound_dimension(self): + """This function returns a valid dimension upper bound of the + simplicial complex. - insert and remove_maximal_simplex functions do not update dimension - value of the `SimplexTree`. + :returns: an upper bound on the dimension of the simplicial complex. + :rtype: int + """ + return self.thisptr.upper_bound_dimension() - `AlphaComplex`, `RipsComplex`, `TangentialComplex` and `WitnessComplex` - automatically sets the correct dimension in their `create_simplex_tree` - functions. + def set_dimension(self, dimension): + """This function sets the dimension of the simplicial complex. :param dimension: The new dimension value. :type dimension: int. + + .. note:: + + This function must be used with caution because it disables + dimension recomputation when required + (this recomputation can be triggered by + :func:`remove_maximal_simplex()<gudhi.SimplexTree.remove_maximal_simplex>` + or + :func:`prune_above_filtration()<gudhi.SimplexTree.prune_above_filtration>` + ). """ self.thisptr.set_dimension(<int>dimension) @@ -182,14 +224,17 @@ cdef class SimplexTree: def insert(self, simplex, filtration=0.0): """This function inserts the given N-simplex and its subfaces with the - given filtration value (default value is '0.0'). + given filtration value (default value is '0.0'). If some of those + simplices are already present with a higher filtration value, their + filtration value is lowered. :param simplex: The N-simplex to insert, represented by a list of vertex. :type simplex: list of int. :param filtration: The filtration value of the simplex. :type filtration: float. - :returns: true if the simplex was found, false otherwise. + :returns: true if the simplex was not yet in the complex, false + otherwise (whatever its original filtration value). :rtype: bool """ cdef vector[int] csimplex @@ -286,9 +331,57 @@ cdef class SimplexTree: :param simplex: The N-simplex, represented by a list of vertex. :type simplex: list of int. + + .. note:: + + Be aware that removing is shifting data in a flat_map + (:func:`initialize_filtration()<gudhi.SimplexTree.initialize_filtration>` to be done). + + .. note:: + + The dimension of the simplicial complex may be lower after calling + remove_maximal_simplex than it was before. However, + :func:`upper_bound_dimension()<gudhi.SimplexTree.upper_bound_dimension>` + method will return the old value, which + remains a valid upper bound. If you care, you can call + :func:`dimension()<gudhi.SimplexTree.dimension>` + to recompute the exact dimension. """ self.thisptr.remove_maximal_simplex(simplex) + def prune_above_filtration(self, filtration): + """Prune above filtration value given as parameter. + + :param filtration: Maximum threshold value. + :type filtration: float. + :returns: The filtration modification information. + :rtype: bint + + + .. note:: + + Some simplex tree functions require the filtration to be valid. + prune_above_filtration 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. + + .. note:: + + Note that the dimension of the simplicial complex may be lower + after calling + :func:`prune_above_filtration()<gudhi.SimplexTree.prune_above_filtration>` + than it was before. However, + :func:`upper_bound_dimension()<gudhi.SimplexTree.upper_bound_dimension>` + will return the old value, which remains a + valid upper bound. If you care, you can call + :func:`dimension()<gudhi.SimplexTree.dimension>` + method to recompute the exact dimension. + """ + return self.thisptr.prune_above_filtration(filtration) + def expansion(self, max_dim): """Expands the Simplex_tree containing only its one skeleton until dimension max_dim. @@ -308,11 +401,31 @@ 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. :param homology_coeff_field: The homology coefficient field. Must be a - prime number + prime number. Default value is 11. :type homology_coeff_field: int. :param min_persistence: The minimum persistence value to take into account (strictly greater than min_persistence). Default value is @@ -336,8 +449,9 @@ cdef class SimplexTree: :returns: The Betti numbers ([B0, B1, ..., Bn]). :rtype: list of int - :note: betti_numbers function requires persistence function to be - launched first. + :note: betti_numbers function requires + :func:`persistence()<gudhi.SimplexTree.persistence>` + function to be launched first. """ cdef vector[int] bn_result if self.pcohptr != NULL: @@ -361,7 +475,8 @@ cdef class SimplexTree: :returns: The persistent Betti numbers ([B0, B1, ..., Bn]). :rtype: list of int - :note: persistent_betti_numbers function requires persistence + :note: persistent_betti_numbers function requires + :func:`persistence()<gudhi.SimplexTree.persistence>` function to be launched first. """ cdef vector[int] pbn_result @@ -381,8 +496,9 @@ cdef class SimplexTree: :returns: The persistence intervals. :rtype: list of pair of float - :note: intervals_in_dim function requires persistence function to be - launched first. + :note: intervals_in_dim function requires + :func:`persistence()<gudhi.SimplexTree.persistence>` + function to be launched first. """ cdef vector[pair[double,double]] intervals_result if self.pcohptr != NULL: @@ -392,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: persistence_pairs 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. @@ -399,8 +534,9 @@ cdef class SimplexTree: :param persistence_file: The specific dimension. :type persistence_file: string. - :note: intervals_in_dim function requires persistence function to be - launched first. + :note: intervals_in_dim function requires + :func:`persistence()<gudhi.SimplexTree.persistence>` + function to be launched first. """ if self.pcohptr != NULL: if persistence_file != '': diff --git a/src/cython/cython/strong_witness_complex.pyx b/src/cython/cython/strong_witness_complex.pyx index 770b46f5..74c5cb05 100644 --- a/src/cython/cython/strong_witness_complex.pyx +++ b/src/cython/cython/strong_witness_complex.pyx @@ -8,7 +8,7 @@ from libcpp.utility cimport pair Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ from libcpp.utility cimport pair """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Strong_witness_complex_interface.h" namespace "Gudhi": diff --git a/src/cython/cython/subsampling.pyx b/src/cython/cython/subsampling.pyx index 894a4fbe..e9d61a37 100644 --- a/src/cython/cython/subsampling.pyx +++ b/src/cython/cython/subsampling.pyx @@ -10,7 +10,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -27,7 +27,7 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Subsampling_interface.h" namespace "Gudhi::subsampling": @@ -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 d55bb050..4bb07076 100644 --- a/src/cython/cython/tangential_complex.pyx +++ b/src/cython/cython/tangential_complex.pyx @@ -11,7 +11,7 @@ import os Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -28,14 +28,14 @@ import os """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __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/cython/witness_complex.pyx b/src/cython/cython/witness_complex.pyx index 96d122bb..8591465a 100644 --- a/src/cython/cython/witness_complex.pyx +++ b/src/cython/cython/witness_complex.pyx @@ -8,7 +8,7 @@ from libcpp.utility cimport pair Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ from libcpp.utility cimport pair """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" cdef extern from "Witness_complex_interface.h" namespace "Gudhi": diff --git a/src/cython/doc/_templates/layout.html b/src/cython/doc/_templates/layout.html index 243f33c6..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,56 +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> - </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> - </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 --> @@ -255,7 +259,7 @@ {%- if hasdoc('copyright') %} {% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %} {%- else %} - {% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} + {% trans copyright=copyright|e %} {{ copyright }}.{% endtrans %} {%- endif %} {%- endif %} {%- if last_updated %} 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 19a880d4..4a54d4fd 100755 --- a/src/cython/doc/conf.py +++ b/src/cython/doc/conf.py @@ -62,7 +62,7 @@ import gudhi # General information about the project. project = gudhi.__name__ -copyright = gudhi.__copyright__ +copyright = gudhi.__copyright__ + ' - ' + gudhi.__license__ # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -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. @@ -158,7 +159,7 @@ html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. 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 2bfac62a..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 @@ -81,23 +85,7 @@ filtration to all cubes. There are a number of constructors that can be used to who want to use the code directly. They can be found in the :doc:`cubical_complex_ref`. Currently one input from a text file is used. It uses a format used already in `Perseus software <http://www.sas.upenn.edu/~vnanda/perseus/>`_ by Vidit Nanda. -Below we are providing a description of the format. The first line contains a number d begin the dimension of the -bitmap (2 in the example below). Next d lines are the numbers of top dimensional cubes in each dimensions (3 and 3 -in the example below). Next, in lexicographical order, the filtration of top dimensional cubes is given (1 4 6 8 -20 4 7 6 5 in the example below). - -.. figure:: - ../../doc/Bitmap_cubical_complex/exampleBitmap.png - :alt: Example of a input data. - :figclass: align-center - - Example of a input data. - -The input file for the following complex is: - -.. literalinclude:: ../../data/bitmap/cubicalcomplexdoc.txt - -.. centered:: ../../data/bitmap/cubicalcomplexdoc.txt +The file format is described here: :doc:`Perseus <fileformats>`. .. testcode:: @@ -124,15 +112,9 @@ Imposing periodic boundary conditions in the direction i, means that the left an :math:`\mathcal{K}` are considered the same. In particular, if for a bitmap :math:`\mathcal{K}` periodic boundary conditions are imposed in all directions, then complex :math:`\mathcal{K}` became n-dimensional torus. One can use various constructors from the file Bitmap_cubical_complex_periodic_boundary_conditions_base.h to construct cubical -complex with periodic boundary conditions. One can also use Perseus style input files. To indicate periodic boundary -conditions in a given direction, then number of top dimensional cells in this direction have to be multiplied by -1. -For instance: +complex with periodic boundary conditions. -.. literalinclude:: ../../data/bitmap/periodiccubicalcomplexdoc.txt - -.. centered:: ../../data/bitmap/periodiccubicalcomplexdoc.txt - -Indicate that we have imposed periodic boundary conditions in the direction x, but not in the direction y. +One can also use Perseus style input files (see :doc:`Perseus <fileformats>`) for the specific periodic case: .. testcode:: @@ -149,6 +131,24 @@ the program output is: Periodic cubical complex is of dimension 2 - 42 simplices. +Or it can be defined as follows: + +.. testcode:: + + from gudhi import PeriodicCubicalComplex as pcc + periodic_cc = pcc(dimensions=[3,3], + top_dimensional_cells= [0, 0, 0, 0, 1, 0, 0, 0, 0], + periodic_dimensions=[True, False]) + result_str = 'Periodic cubical complex is of dimension ' + repr(periodic_cc.dimension()) + ' - ' + \ + repr(periodic_cc.num_simplices()) + ' simplices.' + print(result_str) + +the program output is: + +.. testoutput:: + + Periodic cubical complex is of dimension 2 - 42 simplices. + Examples. --------- @@ -157,6 +157,6 @@ End user programs are available in cython/example/ folder. Bibliography ============ -.. bibliography:: ../../bibliography.bib +.. bibliography:: ../../biblio/bibliography.bib :filter: docnames :style: unsrt 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 156ef4e4..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 ############ @@ -23,7 +27,7 @@ Here is a simple sample file:: 3 34.2 34.974 4 3. inf -Other sample files can be found in the data/persistence_diagram folder. +Other sample files can be found in the `data/persistence_diagram` folder. Such files can be generated with :meth:`gudhi.SimplexTree.write_persistence_diagram`, read with @@ -31,3 +35,56 @@ Such files can be generated with :meth:`gudhi.read_persistence_intervals_in_dimension` and displayed with :meth:`gudhi.plot_persistence_barcode` or :meth:`gudhi.plot_persistence_diagram`. + +Iso-cuboid +********** + +Such a file describes an iso-oriented cuboid with diagonal opposite vertices +(min_x, min_y, min_z,...) and (max_x, max_y, max_z, ...). The format is:: + + min_x min_y [min_z ...] + max_x max_y [max_z ...] + +Here is a simple sample file in the 3D case:: + + -1. -1. -1. + 1. 1. 1. + + +Perseus +******* + +This file format is the format used by the +`Perseus software <http://www.sas.upenn.edu/~vnanda/perseus/>`_ by Vidit Nanda. +The first line contains a number d begin the dimension of the bitmap (2 in the +example below). Next d lines are the numbers of top dimensional cubes in each +dimensions (3 and 3 in the example below). Next, in lexicographical order, the +filtration of top dimensional cubes is given (1 4 6 8 20 4 7 6 5 in the example +below). + +.. figure:: + ../../doc/Bitmap_cubical_complex/exampleBitmap.png + :alt: Example of a input data. + :figclass: align-center + + Example of a input data. + +The input file for the following complex is: + +.. literalinclude:: ../../data/bitmap/cubicalcomplexdoc.txt + +.. centered:: ../../data/bitmap/cubicalcomplexdoc.txt + +To indicate periodic boundary conditions in a given direction, then number of +top dimensional cells in this direction have to be multiplied by -1. For +instance: + +.. literalinclude:: ../../data/bitmap/periodiccubicalcomplexdoc.txt + +.. centered:: ../../data/bitmap/periodiccubicalcomplexdoc.txt + + +Indicate that we have imposed periodic boundary conditions in the direction x, +but not in the direction y. + +Other sample files can be found in the `data/bitmap` folder. 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..ef2f7af2 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 ============= @@ -136,7 +195,7 @@ The following examples require the `Matplotlib <http://matplotlib.org>`_: * :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>` * :download:`euclidean_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py>` -Numpy +NumPy ===== The :doc:`persistence graphical tools </persistence_graphical_tools_user>` @@ -157,6 +216,13 @@ The following examples require the `NumPy <http://numpy.org>`_: * :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>` * :download:`euclidean_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_witness_complex_diagram_persistence_from_off_file_example.py>` +SciPy +===== + +The :doc:`persistence graphical tools </persistence_graphical_tools_user>` +module requires `SciPy <http://scipy.org>`_, a Python-based ecosystem of +open-source software for mathematics, science, and engineering. + Threading Building Blocks ========================= 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..523c119f --- /dev/null +++ b/src/cython/doc/nerve_gic_complex_sum.rst @@ -0,0 +1,15 @@ +================================================================= =================================== =================================== +:Author: Mathieu Carrière :Introduced in: GUDHI 2.3.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..54aff4bc 100644 --- a/src/cython/doc/persistence_graphical_tools_ref.rst +++ b/src/cython/doc/persistence_graphical_tools_ref.rst @@ -1,8 +1,12 @@ +: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 +.. autofunction:: gudhi.plot_persistence_density diff --git a/src/cython/doc/persistence_graphical_tools_sum.rst b/src/cython/doc/persistence_graphical_tools_sum.inc index d602daa7..5577cf99 100644 --- a/src/cython/doc/persistence_graphical_tools_sum.rst +++ b/src/cython/doc/persistence_graphical_tools_sum.inc @@ -1,11 +1,11 @@ ================================================================= =================================== =================================== :Author: Vincent Rouvreau :Introduced in: GUDHI 2.0.0 :Copyright: GPL v3 -:Requires: Matplotlib Numpy +:Requires: matplotlib numpy scipy ================================================================= =================================== =================================== +-----------------------------------------------------------------+-----------------------------------------------------------------------+ | .. figure:: | These graphical tools comes on top of persistence results and allows | -| img/graphical_tools_representation.png | the user to build easily barcode and persistence diagram. | +| img/graphical_tools_representation.png | the user to build easily persistence barcode, diagram or density. | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------------+ | :doc:`persistence_graphical_tools_user` | :doc:`persistence_graphical_tools_ref` | diff --git a/src/cython/doc/persistence_graphical_tools_user.rst b/src/cython/doc/persistence_graphical_tools_user.rst index 9033331f..b2124fdd 100644 --- a/src/cython/doc/persistence_graphical_tools_user.rst +++ b/src/cython/doc/persistence_graphical_tools_user.rst @@ -1,77 +1,73 @@ +: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 +.. include:: persistence_graphical_tools_sum.inc -Show palette values -------------------- +Show persistence as a barcode +----------------------------- -This function is useful to show the color palette values of dimension: +.. note:: + this function requires matplotlib and numpy to be available +This function can display the persistence result as a barcode: -.. testcode:: +.. plot:: + :include-source: import gudhi - plt = gudhi.show_palette_values(alpha=1.0) - plt.show() -.. plot:: + off_file = gudhi.__root_source_dir__ + '/data/points/tore3D_300.off' + point_cloud = gudhi.read_off(off_file=off_file) - import gudhi - plt = gudhi.show_palette_values(alpha=1.0) - plt.show() + rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=0.7) + simplex_tree = rips_complex.create_simplex_tree(max_dimension=3) + diag = simplex_tree.persistence(min_persistence=0.4) -Show persistence as a barcode ------------------------------ + plot = gudhi.plot_persistence_barcode(diag) + plot.show() -This function can display the persistence result as a barcode: +Show persistence as a diagram +----------------------------- -.. testcode:: +.. note:: + this function requires matplotlib and numpy to be available - 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() +This function can display the persistence result as a diagram: .. plot:: + :include-source: import gudhi - periodic_cc = gudhi.PeriodicCubicalComplex(perseus_file=gudhi.__root_source_dir__ + \ - '/data/bitmap/3d_torus.txt') - diag = periodic_cc.persistence() - print("diag = ", diag) - plt = gudhi.plot_persistence_barcode(diag) + # 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() -Show persistence as a diagram ------------------------------ - -This function can display the persistence result as a diagram: +Persistence density +------------------- -.. testcode:: +.. note:: + this function requires matplotlib, numpy and scipy to be available - import gudhi - - rips_complex = gudhi.RipsComplex(off_file=gudhi.__root_source_dir__ + \ - '/data/points/tore3D_1307.off', 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() +If you want more information on a specific dimension, for instance: .. plot:: + :include-source: import gudhi - rips_complex = gudhi.RipsComplex(off_file=gudhi.__root_source_dir__ + \ - '/data/points/tore3D_1307.off', 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_density(persistence_file=persistence_file, + max_intervals=0, dimension=1, legend=True) 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 c2fbf801..00000000 --- a/src/cython/doc/pyplots/diagram_persistence.py +++ /dev/null @@ -1,8 +0,0 @@ -import gudhi - -rips_complex = gudhi.RipsComplex(off_file=gudhi.__root_source_dir__ + \ - '/data/points/tore3D_1307.off', 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/python3-sphinx-build.py b/src/cython/doc/python3-sphinx-build.py index 44b94169..84d158cf 100755 --- a/src/cython/doc/python3-sphinx-build.py +++ b/src/cython/doc/python3-sphinx-build.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 """ Emulate sphinx-build for python3 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 96ba9944..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 @@ -101,8 +105,8 @@ Finally, it is asked to display information about the Rips complex. .. testcode:: import gudhi - rips_complex = gudhi.RipsComplex(off_file=gudhi.__root_source_dir__ + \ - '/data/points/alphacomplexdoc.off', max_edge_length=12.0) + point_cloud = gudhi.read_off(off_file=gudhi.__root_source_dir__ + '/data/points/alphacomplexdoc.off') + rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=12.0) simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ repr(simplex_tree.num_simplices()) + ' simplices - ' + \ @@ -197,7 +201,7 @@ Example from csv file ^^^^^^^^^^^^^^^^^^^^^ This example builds the :doc:`Rips_complex <rips_complex_ref>` from the given -points in an OFF file, and max_edge_length value. +distance matrix in a csv file, and max_edge_length value. Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it. Finally, it is asked to display information about the Rips complex. @@ -206,8 +210,9 @@ Finally, it is asked to display information about the Rips complex. .. testcode:: import gudhi - rips_complex = gudhi.RipsComplex(csv_file=gudhi.__root_source_dir__ + \ - '/data/distance_matrix/full_square_distance_matrix.csv', max_edge_length=12.0) + distance_matrix = gudhi.read_lower_triangular_matrix_from_csv_file(csv_file=gudhi.__root_source_dir__ + \ + '/data/distance_matrix/full_square_distance_matrix.csv') + rips_complex = gudhi.RipsComplex(distance_matrix=distance_matrix, max_edge_length=12.0) simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ repr(simplex_tree.num_simplices()) + ' simplices - ' + \ @@ -240,3 +245,72 @@ the program output is: [0, 3] -> 9.43 [4, 6] -> 9.49 [3, 6] -> 11.00 + +Correlation matrix +------------------ + +Example from a correlation matrix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Analogously to the case of distance matrix, Rips complexes can be also constructed based on correlation matrix. +Given a correlation matrix M, comportment-wise 1-M is a distance matrix. +This example builds the one skeleton graph from the given corelation matrix and threshold value. +Then it creates a :doc:`Simplex_tree <simplex_tree_ref>` with it. + +Finally, it is asked to display information about the simplicial complex. + +.. testcode:: + + import gudhi + import numpy as np + + # User defined correlation matrix is: + # |1 0.06 0.23 0.01 0.89| + # |0.06 1 0.74 0.01 0.61| + # |0.23 0.74 1 0.72 0.03| + # |0.01 0.01 0.72 1 0.7 | + # |0.89 0.61 0.03 0.7 1 | + correlation_matrix=np.array([[1., 0.06, 0.23, 0.01, 0.89], + [0.06, 1., 0.74, 0.01, 0.61], + [0.23, 0.74, 1., 0.72, 0.03], + [0.01, 0.01, 0.72, 1., 0.7], + [0.89, 0.61, 0.03, 0.7, 1.]], float) + + distance_matrix = np.ones((correlation_matrix.shape),float) - correlation_matrix + rips_complex = gudhi.RipsComplex(distance_matrix=distance_matrix, max_edge_length=1.0) + + simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) + result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + fmt = '%s -> %.2f' + for filtered_value in simplex_tree.get_filtration(): + print(fmt % tuple(filtered_value)) + +When launching (Rips maximal distance between 2 points is 12.0, is expanded +until dimension 1 - one skeleton graph in other words), the output is: + +.. testoutput:: + + Rips complex is of dimension 1 - 15 simplices - 5 vertices. + [0] -> 0.00 + [1] -> 0.00 + [2] -> 0.00 + [3] -> 0.00 + [4] -> 0.00 + [0, 4] -> 0.11 + [1, 2] -> 0.26 + [2, 3] -> 0.28 + [3, 4] -> 0.30 + [1, 4] -> 0.39 + [0, 2] -> 0.77 + [0, 1] -> 0.94 + [2, 4] -> 0.97 + [0, 3] -> 0.99 + [1, 3] -> 0.99 + +.. note:: + As persistence diagrams points will be under the diagonal, + bottleneck distance and persistence graphical tool will not work properly, + this is a known issue. 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 29413269..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 ----------- @@ -121,7 +125,7 @@ Example2: Computing persistence using strong relaxed witness complex Here is an example of constructing a strong witness complex filtration and computing persistence on it: -* :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py>` +* :download:`euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py <../example/euclidean_strong_witness_complex_diagram_persistence_from_off_file_example.py>` Bibliography ============ 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 b4487be4..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 @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='AlphaComplex creation from ' @@ -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/alpha_complex_from_points_example.py b/src/cython/example/alpha_complex_from_points_example.py index 7d6278ce..ad73c744 100755 --- a/src/cython/example/alpha_complex_from_points_example.py +++ b/src/cython/example/alpha_complex_from_points_example.py @@ -8,7 +8,7 @@ from gudhi import AlphaComplex, SimplexTree Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ from gudhi import AlphaComplex, SimplexTree """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" print("#####################################################################") diff --git a/src/cython/example/alpha_rips_persistence_bottleneck_distance.py b/src/cython/example/alpha_rips_persistence_bottleneck_distance.py index ab5fc1e9..b51fa7a8 100755 --- a/src/cython/example/alpha_rips_persistence_bottleneck_distance.py +++ b/src/cython/example/alpha_rips_persistence_bottleneck_distance.py @@ -10,7 +10,7 @@ import math Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -27,7 +27,7 @@ import math """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='AlphaComplex and RipsComplex ' @@ -45,13 +45,14 @@ args = parser.parse_args() with open(args.file, 'r') as f: first_line = f.readline() if (first_line == 'OFF\n') or (first_line == 'nOFF\n'): + point_cloud = gudhi.read_off(off_file=args.file) print("#####################################################################") print("RipsComplex creation from points read in a OFF file") message = "RipsComplex with max_edge_length=" + repr(args.threshold) print(message) - rips_complex = gudhi.RipsComplex(off_file=args.file, + rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=args.threshold) rips_stree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) @@ -67,7 +68,7 @@ with open(args.file, 'r') as f: message = "AlphaComplex with max_edge_length=" + repr(args.threshold) print(message) - alpha_complex = gudhi.AlphaComplex(off_file=args.file) + alpha_complex = gudhi.AlphaComplex(points=point_cloud) alpha_stree = alpha_complex.create_simplex_tree(max_alpha_square=(args.threshold * args.threshold)) message = "Number of simplices=" + repr(alpha_stree.num_simplices()) diff --git a/src/cython/example/bottleneck_basic_example.py b/src/cython/example/bottleneck_basic_example.py index 31cecb29..287956e7 100755 --- a/src/cython/example/bottleneck_basic_example.py +++ b/src/cython/example/bottleneck_basic_example.py @@ -8,7 +8,7 @@ import gudhi Author(s): Francois Godi, Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,11 +25,9 @@ import gudhi """ __author__ = "Francois Godi, Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" -import gudhi - diag1 = [[2.7, 3.7],[9.6, 14.],[34.2, 34.974], [3.,float('Inf')]] diag2 = [[2.8, 4.45],[9.5, 14.1],[3.2,float('Inf')]] 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 e3f362dc..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 @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='EuclideanStrongWitnessComplex creation from ' @@ -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 c236d992..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 @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='EuclideanWitnessComplex creation from ' @@ -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 ed87806b..ac3d146c 100755 --- a/src/cython/example/gudhi_graphical_tools_example.py +++ b/src/cython/example/gudhi_graphical_tools_example.py @@ -8,7 +8,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,15 +25,10 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__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/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py b/src/cython/example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py index 00334121..5f968bf1 100755 --- a/src/cython/example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py +++ b/src/cython/example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" def is_file_perseus(file): diff --git a/src/cython/example/random_cubical_complex_persistence_example.py b/src/cython/example/random_cubical_complex_persistence_example.py index c832d6bf..80ff2452 100755 --- a/src/cython/example/random_cubical_complex_persistence_example.py +++ b/src/cython/example/random_cubical_complex_persistence_example.py @@ -13,7 +13,7 @@ import operator Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -30,7 +30,7 @@ import operator """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='Random cubical complex.', diff --git a/src/cython/example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py b/src/cython/example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py new file mode 100755 index 00000000..0c9dfc43 --- /dev/null +++ b/src/cython/example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +import gudhi +import sys +import argparse + +"""This file is part of the Gudhi Library. The Gudhi library + (Geometric Understanding in Higher Dimensions) is a generic C++ + library for computational topology. + + Author(s): Vincent Rouvreau + + Copyright (C) 2017 Inria + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2017 Inria" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='RipsComplex creation from ' + 'a correlation matrix read in a csv file.', + epilog='Example: ' + 'example/rips_complex_diagram_persistence_from_correlation_matrix_file_example.py ' + '-f ../data/correlation_matrix/lower_triangular_correlation_matrix.csv -e 12.0 -d 3' + '- Constructs a Rips complex with the ' + 'correlation matrix from the given csv file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-c", "--min_edge_correlation", type=float, default=0.5) +parser.add_argument("-d", "--max_dimension", type=int, default=1) +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() + +if not (-1. < args.min_edge_correlation < 1.): + print("Wrong value of the treshold corelation (should be between -1 and 1).") + sys.exit(1) + +print("#####################################################################") +print("Caution: as persistence diagrams points will be under the diagonal,") +print("bottleneck distance and persistence graphical tool will not work") +print("properly, this is a known issue.") + +print("#####################################################################") +print("RipsComplex creation from correlation matrix read in a csv file") + +message = "RipsComplex with min_edge_correlation=" + repr(args.min_edge_correlation) +print(message) + +correlation_matrix = gudhi.read_lower_triangular_matrix_from_csv_file(csv_file=args.file) +# Given a correlation matrix M, we compute component-wise M'[i,j] = 1-M[i,j] to get a distance matrix: +distance_matrix = [[1.-correlation_matrix[i][j] for j in range(len(correlation_matrix[i]))] for i in range(len(correlation_matrix))] + +rips_complex = gudhi.RipsComplex(distance_matrix=distance_matrix, + max_edge_length=1.-args.min_edge_correlation) +simplex_tree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) + +message = "Number of simplices=" + repr(simplex_tree.num_simplices()) +print(message) + +diag = simplex_tree.persistence() + +print("betti_numbers()=") +print(simplex_tree.betti_numbers()) + +# invert the persistence diagram +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=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 3baebd17..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 @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,20 +26,20 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='RipsComplex creation from ' - 'a distance matrix read in a OFF file.', + 'a distance matrix read in a csv file.', epilog='Example: ' 'example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py ' '-f ../data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3' '- Constructs a Rips complex with the ' - 'points from the given OFF file.') + 'distance matrix from the given csv file.') parser.add_argument("-f", "--file", type=str, required=True) parser.add_argument("-e", "--max_edge_length", type=float, default=0.5) parser.add_argument("-d", "--max_dimension", type=int, default=1) -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() @@ -50,7 +50,8 @@ print("RipsComplex creation from distance matrix read in a csv file") message = "RipsComplex with max_edge_length=" + repr(args.max_edge_length) print(message) -rips_complex = gudhi.RipsComplex(csv_file=args.file, max_edge_length=args.max_edge_length) +distance_matrix = gudhi.read_lower_triangular_matrix_from_csv_file(csv_file=args.file) +rips_complex = gudhi.RipsComplex(distance_matrix=distance_matrix, max_edge_length=args.max_edge_length) simplex_tree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) message = "Number of simplices=" + repr(simplex_tree.num_simplices()) @@ -62,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 5951eedf..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 @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,7 +26,7 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" parser = argparse.ArgumentParser(description='RipsComplex creation from ' @@ -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() @@ -53,7 +53,8 @@ with open(args.file, 'r') as f: message = "RipsComplex with max_edge_length=" + repr(args.max_edge_length) print(message) - rips_complex = gudhi.RipsComplex(off_file=args.file, max_edge_length=args.max_edge_length) + point_cloud = gudhi.read_off(off_file=args.file) + rips_complex = gudhi.RipsComplex(points=point_cloud, max_edge_length=args.max_edge_length) simplex_tree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) message = "Number of simplices=" + repr(simplex_tree.num_simplices()) @@ -65,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/rips_complex_from_points_example.py b/src/cython/example/rips_complex_from_points_example.py index 5d411b1a..ffa9d91f 100755 --- a/src/cython/example/rips_complex_from_points_example.py +++ b/src/cython/example/rips_complex_from_points_example.py @@ -8,7 +8,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" print("#####################################################################") diff --git a/src/cython/example/rips_persistence_diagram.py b/src/cython/example/rips_persistence_diagram.py index 9bfea41c..7a6a9f46 100755 --- a/src/cython/example/rips_persistence_diagram.py +++ b/src/cython/example/rips_persistence_diagram.py @@ -8,7 +8,7 @@ import gudhi Author(s): Marc Glisse - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ import gudhi """ __author__ = "Marc Glisse" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" print("#####################################################################") diff --git a/src/cython/example/simplex_tree_example.py b/src/cython/example/simplex_tree_example.py index 831d9da8..28679015 100755 --- a/src/cython/example/simplex_tree_example.py +++ b/src/cython/example/simplex_tree_example.py @@ -8,7 +8,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" print("#####################################################################") @@ -48,8 +48,6 @@ if st.insert([0, 1, 2], filtration=4.0): else: print("Not inserted...") -# FIXME: Remove this line -st.set_dimension(3) print("dimension=", st.dimension()) st.initialize_filtration() diff --git a/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py b/src/cython/example/tangential_complex_plain_homology_from_off_file_example.py index 6145e7f2..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 @@ -9,7 +9,7 @@ import argparse Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -26,18 +26,19 @@ import argparse """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" 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/example/witness_complex_from_nearest_landmark_table.py b/src/cython/example/witness_complex_from_nearest_landmark_table.py index 92ed970b..e6b295ee 100755 --- a/src/cython/example/witness_complex_from_nearest_landmark_table.py +++ b/src/cython/example/witness_complex_from_nearest_landmark_table.py @@ -8,7 +8,7 @@ from gudhi import StrongWitnessComplex, SimplexTree Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -25,7 +25,7 @@ from gudhi import StrongWitnessComplex, SimplexTree """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" print("#####################################################################") diff --git a/src/cython/gudhi.pyx.in b/src/cython/gudhi.pyx.in index a8dd9f80..0d4b966b 100644 --- a/src/cython/gudhi.pyx.in +++ b/src/cython/gudhi.pyx.in @@ -4,7 +4,7 @@ Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -21,11 +21,12 @@ """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __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/Alpha_complex_interface.h b/src/cython/include/Alpha_complex_interface.h index d47db71f..faa059d1 100644 --- a/src/cython/include/Alpha_complex_interface.h +++ b/src/cython/include/Alpha_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 @@ -60,7 +60,7 @@ class Alpha_complex_interface { Point_d ph = alpha_complex_->get_point(vh); for (auto coord = ph.cartesian_begin(); coord < ph.cartesian_end(); coord++) vd.push_back(*coord); - } catch (std::out_of_range outofrange) { + } catch (std::out_of_range const&) { // std::out_of_range is thrown in case not found. Other exceptions must be re-thrown } return vd; diff --git a/src/cython/include/Bottleneck_distance_interface.h b/src/cython/include/Bottleneck_distance_interface.h index d5fbf6ea..5ad9d77d 100644 --- a/src/cython/include/Bottleneck_distance_interface.h +++ b/src/cython/include/Bottleneck_distance_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 diff --git a/src/cython/include/Cubical_complex_interface.h b/src/cython/include/Cubical_complex_interface.h index 7c0148f1..85b717b3 100644 --- a/src/cython/include/Cubical_complex_interface.h +++ b/src/cython/include/Cubical_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 @@ -43,6 +43,12 @@ class Cubical_complex_interface : public Bitmap_cubical_complex<CubicalComplexOp : Bitmap_cubical_complex<CubicalComplexOptions>(dimensions, top_dimensional_cells) { } + Cubical_complex_interface(const std::vector<unsigned>& dimensions, + const std::vector<double>& top_dimensional_cells, + const std::vector<bool>& periodic_dimensions) + : Bitmap_cubical_complex<CubicalComplexOptions>(dimensions, top_dimensional_cells, periodic_dimensions) { + } + Cubical_complex_interface(const std::string& perseus_file) : Bitmap_cubical_complex<CubicalComplexOptions>(perseus_file.c_str()) { } diff --git a/src/cython/include/Euclidean_strong_witness_complex_interface.h b/src/cython/include/Euclidean_strong_witness_complex_interface.h index b9dd8177..d86355d6 100644 --- a/src/cython/include/Euclidean_strong_witness_complex_interface.h +++ b/src/cython/include/Euclidean_strong_witness_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 diff --git a/src/cython/include/Euclidean_witness_complex_interface.h b/src/cython/include/Euclidean_witness_complex_interface.h index 2a09b3b5..dc303533 100644 --- a/src/cython/include/Euclidean_witness_complex_interface.h +++ b/src/cython/include/Euclidean_witness_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 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/Off_reader_interface.h b/src/cython/include/Off_reader_interface.h index 0ca55500..f6b14f38 100644 --- a/src/cython/include/Off_reader_interface.h +++ b/src/cython/include/Off_reader_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 diff --git a/src/cython/include/Persistent_cohomology_interface.h b/src/cython/include/Persistent_cohomology_interface.h index 55028fd0..8cf71a4e 100644 --- a/src/cython/include/Persistent_cohomology_interface.h +++ b/src/cython/include/Persistent_cohomology_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 @@ -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/Reader_utils_interface.h b/src/cython/include/Reader_utils_interface.h index 8ec34f61..5f7527d9 100644 --- a/src/cython/include/Reader_utils_interface.h +++ b/src/cython/include/Reader_utils_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2017 INRIA + * Copyright (C) 2017 Inria * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/cython/include/Rips_complex_interface.h b/src/cython/include/Rips_complex_interface.h index 02985727..8b6c9c35 100644 --- a/src/cython/include/Rips_complex_interface.h +++ b/src/cython/include/Rips_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 @@ -25,9 +25,7 @@ #include <gudhi/Simplex_tree.h> #include <gudhi/Rips_complex.h> -#include <gudhi/Points_off_io.h> #include <gudhi/distance_functions.h> -#include <gudhi/reader_utils.h> #include "Simplex_tree_interface.h" @@ -56,21 +54,6 @@ class Rips_complex_interface { } } - Rips_complex_interface(const std::string& file_name, double threshold, bool euclidean, bool from_file = true) { - if (euclidean) { - // Rips construction where file_name is an OFF file - Gudhi::Points_off_reader<Point_d> off_reader(file_name); - rips_complex_ = new Rips_complex<Simplex_tree_interface<>::Filtration_value>(off_reader.get_point_cloud(), - threshold, - Gudhi::Euclidean_distance()); - } else { - // Rips construction where values is a distance matrix - Distance_matrix distances = - Gudhi::read_lower_triangular_matrix_from_csv_file<Simplex_tree_interface<>::Filtration_value>(file_name); - rips_complex_ = new Rips_complex<Simplex_tree_interface<>::Filtration_value>(distances, threshold); - } - } - ~Rips_complex_interface() { delete rips_complex_; } diff --git a/src/cython/include/Simplex_tree_interface.h b/src/cython/include/Simplex_tree_interface.h index 09e7e992..3481eeff 100644 --- a/src/cython/include/Simplex_tree_interface.h +++ b/src/cython/include/Simplex_tree_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 @@ -52,6 +52,10 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> { return (Base::find(vh) != Base::null_simplex()); } + void assign_simplex_filtration(const Simplex& vh, Filtration_value filtration) { + Base::assign_filtration(Base::find(vh), filtration); + } + bool insert(const Simplex& simplex, Filtration_value filtration = 0) { Insertion_result result = Base::insert_simplex_and_subfaces(simplex, filtration); return (result.second); diff --git a/src/cython/include/Strong_witness_complex_interface.h b/src/cython/include/Strong_witness_complex_interface.h index d05eaac5..3c72c916 100644 --- a/src/cython/include/Strong_witness_complex_interface.h +++ b/src/cython/include/Strong_witness_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 diff --git a/src/cython/include/Subsampling_interface.h b/src/cython/include/Subsampling_interface.h index b0f4a50a..f990da0c 100644 --- a/src/cython/include/Subsampling_interface.h +++ b/src/cython/include/Subsampling_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 diff --git a/src/cython/include/Tangential_complex_interface.h b/src/cython/include/Tangential_complex_interface.h index 5e9dc0e4..71418886 100644 --- a/src/cython/include/Tangential_complex_interface.h +++ b/src/cython/include/Tangential_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 @@ -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(); @@ -105,9 +100,7 @@ class Tangential_complex_interface { } void create_simplex_tree(Simplex_tree<>* simplex_tree) { - int max_dim = tangential_complex_->create_complex<Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_full_featured>>(*simplex_tree); - // FIXME - simplex_tree->set_dimension(max_dim); + tangential_complex_->create_complex<Gudhi::Simplex_tree<Gudhi::Simplex_tree_options_full_featured>>(*simplex_tree); simplex_tree->initialize_filtration(); } diff --git a/src/cython/include/Witness_complex_interface.h b/src/cython/include/Witness_complex_interface.h index 6501cc35..01b372e7 100644 --- a/src/cython/include/Witness_complex_interface.h +++ b/src/cython/include/Witness_complex_interface.h @@ -4,7 +4,7 @@ * * Author(s): Vincent Rouvreau * - * Copyright (C) 2016 INRIA + * Copyright (C) 2016 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 diff --git a/src/cython/setup.py.in b/src/cython/setup.py.in index fefa36bb..4037aab6 100644 --- a/src/cython/setup.py.in +++ b/src/cython/setup.py.in @@ -7,7 +7,7 @@ from Cython.Build import cythonize Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,8 +23,8 @@ from Cython.Build import cythonize along with this program. If not, see <http://www.gnu.org/licenses/>. """ -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__author__ = "GUDHI Editorial Board" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" gudhi = Extension( @@ -41,9 +41,10 @@ gudhi = Extension( setup( name = 'gudhi', - author='Vincent Rouvreau', + author='GUDHI Editorial Board', author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', ext_modules = cythonize(gudhi), + install_requires = ["cython",], ) diff --git a/src/cython/test/test_alpha_complex.py b/src/cython/test/test_alpha_complex.py index 2c76d9d7..e97f2530 100755 --- a/src/cython/test/test_alpha_complex.py +++ b/src/cython/test/test_alpha_complex.py @@ -6,7 +6,7 @@ from gudhi import AlphaComplex, SimplexTree Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ from gudhi import AlphaComplex, SimplexTree """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" diff --git a/src/cython/test/test_bottleneck_distance.py b/src/cython/test/test_bottleneck_distance.py index 3d982d34..4eb5848f 100755 --- a/src/cython/test/test_bottleneck_distance.py +++ b/src/cython/test/test_bottleneck_distance.py @@ -6,7 +6,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" 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 9a365823..92e591e9 100755 --- a/src/cython/test/test_cubical_complex.py +++ b/src/cython/test/test_cubical_complex.py @@ -6,7 +6,7 @@ from gudhi import CubicalComplex Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ from gudhi import CubicalComplex """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" @@ -62,17 +62,28 @@ def test_dimension_or_perseus_file_constructor(): assert cub.__is_defined() == False assert cub.__is_persistence_defined() == False -def test_dimension_constructor(): +def test_dimension_simple_constructor(): cub = CubicalComplex(dimensions=[3, 3], top_dimensional_cells = [1,2,3,4,5,6,7,8,9]) assert cub.__is_defined() == True assert cub.__is_persistence_defined() == False - assert cub.persistence() == [(1, (0.0, 100.0)), (0, (0.0, float('inf')))] + assert cub.persistence() == [(0, (1.0, float('inf')))] + assert cub.__is_persistence_defined() == True + 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 - assert cub.betti_numbers() == [1, 0] - assert cub.persistent_betti_numbers(0, 1000) == [0, 0] + 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_constructor(): +def test_dimension_file_constructor(): # Create test file test_file = open('CubicalOneSphere.txt', 'w') test_file.write('2\n3\n3\n0\n0\n0\n0\n100\n0\n0\n0\n0\n') diff --git a/src/cython/test/test_euclidean_witness_complex.py b/src/cython/test/test_euclidean_witness_complex.py index 737f1ef4..2f77210a 100755 --- a/src/cython/test/test_euclidean_witness_complex.py +++ b/src/cython/test/test_euclidean_witness_complex.py @@ -6,7 +6,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" diff --git a/src/cython/test/test_reader_utils.py b/src/cython/test/test_reader_utils.py index 25591fb3..b240c84f 100755 --- a/src/cython/test/test_reader_utils.py +++ b/src/cython/test/test_reader_utils.py @@ -6,7 +6,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2017 INRIA + Copyright (C) 2017 Inria This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2017 INRIA" +__copyright__ = "Copyright (C) 2017 Inria" __license__ = "GPL v3" diff --git a/src/cython/test/test_rips_complex.py b/src/cython/test/test_rips_complex.py index c7d2ead4..c37b5400 100755 --- a/src/cython/test/test_rips_complex.py +++ b/src/cython/test/test_rips_complex.py @@ -7,7 +7,7 @@ from math import sqrt Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -24,7 +24,7 @@ from math import sqrt """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" diff --git a/src/cython/test/test_simplex_tree.py b/src/cython/test/test_simplex_tree.py index 4d452d7d..cb701c9a 100755 --- a/src/cython/test/test_simplex_tree.py +++ b/src/cython/test/test_simplex_tree.py @@ -6,7 +6,7 @@ from gudhi import SimplexTree Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ from gudhi import SimplexTree """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" @@ -34,9 +34,13 @@ def test_insertion(): # insert test assert st.insert([0, 1]) == True + + assert st.dimension() == 1 + assert st.insert([0, 1, 2], filtration=4.0) == True - # FIXME: Remove this line - st.set_dimension(2) + + assert st.dimension() == 2 + assert st.num_simplices() == 7 assert st.num_vertices() == 3 @@ -86,8 +90,9 @@ def test_insertion(): assert st.find([2]) == True st.initialize_filtration() - assert st.persistence() == [(1, (4.0, float('inf'))), (0, (0.0, float('inf')))] + assert st.persistence(persistence_dim_max = True) == [(1, (4.0, float('inf'))), (0, (0.0, float('inf')))] assert st.__is_persistence_defined() == True + assert st.betti_numbers() == [1, 1] assert st.persistent_betti_numbers(-0.1, 10000.0) == [0, 0] assert st.persistent_betti_numbers(0.0, 10000.0) == [1, 0] @@ -129,3 +134,74 @@ def test_expansion(): ([1, 2], 0.5), ([0, 1, 2], 0.5), ([1, 2, 3], 0.5), ([5], 0.6), ([6], 0.6), ([5, 6], 0.6), ([4], 0.7), ([2, 4], 0.7), ([0, 3], 0.8), ([0, 1, 3], 0.8), ([0, 2, 3], 0.8), ([0, 1, 2, 3], 0.8), ([4, 6], 0.9), ([3, 6], 1.0)] + +def test_automatic_dimension(): + st = SimplexTree() + assert st.__is_defined() == True + assert st.__is_persistence_defined() == False + + # insert test + assert st.insert([0,1,3], filtration=0.5) == True + assert st.insert([0,1,2], filtration=1.) == True + + assert st.num_vertices() == 4 + assert st.num_simplices() == 11 + + assert st.dimension() == 2 + assert st.upper_bound_dimension() == 2 + + assert st.prune_above_filtration(0.6) == True + assert st.dimension() == 2 + assert st.upper_bound_dimension() == 2 + + st.assign_filtration([0, 1, 3], 0.7) + assert st.filtration([0, 1, 3]) == 0.7 + + st.remove_maximal_simplex([0, 1, 3]) + 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_subsampling.py b/src/cython/test/test_subsampling.py index 2caf4ddb..96906a6f 100755 --- a/src/cython/test/test_subsampling.py +++ b/src/cython/test/test_subsampling.py @@ -6,7 +6,7 @@ import gudhi Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ import gudhi """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" diff --git a/src/cython/test/test_tangential_complex.py b/src/cython/test/test_tangential_complex.py index 8aa4023c..5385a0d3 100755 --- a/src/cython/test/test_tangential_complex.py +++ b/src/cython/test/test_tangential_complex.py @@ -6,7 +6,7 @@ from gudhi import TangentialComplex, SimplexTree Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,13 +23,13 @@ from gudhi import TangentialComplex, SimplexTree """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __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 diff --git a/src/cython/test/test_witness_complex.py b/src/cython/test/test_witness_complex.py index 7d1fb6be..bcbc521b 100755 --- a/src/cython/test/test_witness_complex.py +++ b/src/cython/test/test_witness_complex.py @@ -6,7 +6,7 @@ from gudhi import WitnessComplex, StrongWitnessComplex, SimplexTree Author(s): Vincent Rouvreau - Copyright (C) 2016 INRIA + Copyright (C) 2016 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 @@ -23,7 +23,7 @@ from gudhi import WitnessComplex, StrongWitnessComplex, SimplexTree """ __author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" +__copyright__ = "Copyright (C) 2016 Inria" __license__ = "GPL v3" |