From 15f222eecf3b427c59f09ec3bec17983377d96a2 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 25 Dec 2019 22:27:52 +0100 Subject: Copy hera headers in user_version --- src/cmake/modules/GUDHI_user_version_target.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cmake/modules/GUDHI_user_version_target.cmake b/src/cmake/modules/GUDHI_user_version_target.cmake index 4fa74330..2527dee9 100644 --- a/src/cmake/modules/GUDHI_user_version_target.cmake +++ b/src/cmake/modules/GUDHI_user_version_target.cmake @@ -56,6 +56,9 @@ add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/GudhUI ${GUDHI_USER_VERSION_DIR}/GudhUI) +add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_SOURCE_DIR}/ext/hera/geom_matching/wasserstein/include ${GUDHI_USER_VERSION_DIR}/hera/wasserstein) + set(GUDHI_DIRECTORIES "doc;example;concept;utilities") set(GUDHI_INCLUDE_DIRECTORIES "include/gudhi") @@ -95,4 +98,4 @@ foreach(GUDHI_MODULE ${GUDHI_MODULES_FULL_LIST}) endforeach() endforeach(GUDHI_INCLUDE_DIRECTORY ${GUDHI_INCLUDE_DIRECTORIES}) -endforeach(GUDHI_MODULE ${GUDHI_MODULES_FULL_LIST}) \ No newline at end of file +endforeach(GUDHI_MODULE ${GUDHI_MODULES_FULL_LIST}) -- cgit v1.2.3 From c2e22942c35e894d5c1ddc429eb32687c61538c8 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 26 Dec 2019 10:22:47 +0100 Subject: Basic binding for wasserstein_distance --- src/cmake/modules/GUDHI_user_version_target.cmake | 2 +- src/python/gudhi/hera.cc | 48 +++++++++++++++++++++++ src/python/setup.py.in | 26 +++++++++++- 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/python/gudhi/hera.cc (limited to 'src') diff --git a/src/cmake/modules/GUDHI_user_version_target.cmake b/src/cmake/modules/GUDHI_user_version_target.cmake index 2527dee9..9a05386f 100644 --- a/src/cmake/modules/GUDHI_user_version_target.cmake +++ b/src/cmake/modules/GUDHI_user_version_target.cmake @@ -57,7 +57,7 @@ add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/GudhUI ${GUDHI_USER_VERSION_DIR}/GudhUI) add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E - copy_directory ${CMAKE_SOURCE_DIR}/ext/hera/geom_matching/wasserstein/include ${GUDHI_USER_VERSION_DIR}/hera/wasserstein) + copy_directory ${CMAKE_SOURCE_DIR}/ext/hera/geom_matching/wasserstein/include ${GUDHI_USER_VERSION_DIR}/ext/hera/geom_matching/wasserstein/include) set(GUDHI_DIRECTORIES "doc;example;concept;utilities") diff --git a/src/python/gudhi/hera.cc b/src/python/gudhi/hera.cc new file mode 100644 index 00000000..7cef9425 --- /dev/null +++ b/src/python/gudhi/hera.cc @@ -0,0 +1,48 @@ +#include +#include + +#include + +#include + +#include + +namespace py = pybind11; +typedef py::array_t Dgm; + +namespace hera { +template <> struct DiagramTraits{ + //using Container = void; + using PointType = std::array; + using RealType = double; + + static RealType get_x(const PointType& p) { return std::get<0>(p); } + static RealType get_y(const PointType& p) { return std::get<1>(p); } +}; +} + +double wasserstein_distance( + Dgm d1, + Dgm d2) +{ + py::buffer_info buf1 = d1.request(); + py::buffer_info buf2 = d2.request(); + if(buf1.ndim!=2 || buf1.shape[1]!=2) + throw std::runtime_error("Diagram 1 must be an array of size n x 2"); + if(buf2.ndim!=2 || buf2.shape[1]!=2) + throw std::runtime_error("Diagram 1 must be an array of size n x 2"); + typedef hera::DiagramTraits::PointType Point; + auto p1 = (Point*)buf1.ptr; + auto p2 = (Point*)buf2.ptr; + auto diag1 = boost::make_iterator_range(p1, p1+buf1.shape[0]); + auto diag2 = boost::make_iterator_range(p2, p2+buf2.shape[0]); + + hera::AuctionParams params; + return hera::wasserstein_dist(diag1, diag2, params); +} + +PYBIND11_MODULE(hera, m) { + m.def("wasserstein_distance", &wasserstein_distance, R"pbdoc( + Compute the Wasserstein distance between two diagrams + )pbdoc"); +} diff --git a/src/python/setup.py.in b/src/python/setup.py.in index 3f1d4424..f7ffd146 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -26,6 +26,19 @@ library_dirs=[@GUDHI_PYTHON_LIBRARY_DIRS@] include_dirs = [numpy_get_include(), '@CMAKE_CURRENT_SOURCE_DIR@/gudhi/', @GUDHI_PYTHON_INCLUDE_DIRS@] runtime_library_dirs=[@GUDHI_PYTHON_RUNTIME_LIBRARY_DIRS@] +class get_pybind_include(object): + """Helper class to determine the pybind11 include path + The purpose of this class is to postpone importing pybind11 + until it is actually installed, so that the ``get_include()`` + method can be invoked. """ + + def __init__(self, user=False): + self.user = user + + def __str__(self): + import pybind11 + return pybind11.get_include(self.user) + # Create ext_modules list from module list ext_modules = [] for module in modules: @@ -39,6 +52,15 @@ for module in modules: library_dirs=library_dirs, include_dirs=include_dirs, runtime_library_dirs=runtime_library_dirs,)) +ext_modules.append(Extension( + 'gudhi.hera', + sources = [source_dir + 'hera.cc'], + language = 'c++', + extra_compile_args=extra_compile_args + ['-fvisibility=hidden'], # FIXME + include_dirs = include_dirs + + ['@CMAKE_SOURCE_DIR@/ext/hera/geom_matching/wasserstein/include', + get_pybind_include(False), get_pybind_include(True)] + )) setup( name = 'gudhi', @@ -48,6 +70,6 @@ setup( version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', ext_modules = cythonize(ext_modules), - install_requires = ['cython','numpy >= 1.9',], - setup_requires = ['numpy >= 1.9',], + install_requires = ['cython','numpy >= 1.9','pybind11',], + setup_requires = ['numpy >= 1.9','pybind11',], ) -- cgit v1.2.3 From 56cee2efaa26e734c9555b5b0bb9dfbbc4baaed8 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 26 Dec 2019 17:33:51 +0100 Subject: Fix compilation --- src/python/CMakeLists.txt | 1 + src/python/setup.py.in | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index b558d4c4..bec38305 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -86,6 +86,7 @@ if(PYTHONINTERP_FOUND) endif(MSVC) if(CMAKE_COMPILER_IS_GNUCXX) set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-frounding-math', ") + set(GUDHI_PYBIND11_EXTRA_COMPILE_ARGS "${GUDHI_PYBIND11_EXTRA_COMPILE_ARGS}'-fvisibility=hidden', ") endif(CMAKE_COMPILER_IS_GNUCXX) if (CMAKE_CXX_COMPILER_ID MATCHES Intel) set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-fp-model strict', ") diff --git a/src/python/setup.py.in b/src/python/setup.py.in index f7ffd146..2d96c57b 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -26,6 +26,7 @@ library_dirs=[@GUDHI_PYTHON_LIBRARY_DIRS@] include_dirs = [numpy_get_include(), '@CMAKE_CURRENT_SOURCE_DIR@/gudhi/', @GUDHI_PYTHON_INCLUDE_DIRS@] runtime_library_dirs=[@GUDHI_PYTHON_RUNTIME_LIBRARY_DIRS@] +# Copied from https://github.com/pybind/python_example/blob/master/setup.py class get_pybind_include(object): """Helper class to determine the pybind11 include path The purpose of this class is to postpone importing pybind11 @@ -52,14 +53,16 @@ for module in modules: library_dirs=library_dirs, include_dirs=include_dirs, runtime_library_dirs=runtime_library_dirs,)) +ext_modules = cythonize(ext_modules) + ext_modules.append(Extension( 'gudhi.hera', sources = [source_dir + 'hera.cc'], language = 'c++', - extra_compile_args=extra_compile_args + ['-fvisibility=hidden'], # FIXME include_dirs = include_dirs + ['@CMAKE_SOURCE_DIR@/ext/hera/geom_matching/wasserstein/include', - get_pybind_include(False), get_pybind_include(True)] + get_pybind_include(False), get_pybind_include(True)], + extra_compile_args=extra_compile_args + [@GUDHI_PYBIND11_EXTRA_COMPILE_ARGS@], )) setup( @@ -69,7 +72,7 @@ setup( author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', - ext_modules = cythonize(ext_modules), + ext_modules = ext_modules, install_requires = ['cython','numpy >= 1.9','pybind11',], setup_requires = ['numpy >= 1.9','pybind11',], ) -- cgit v1.2.3 From 4922f305b7601d9e5d7eb39c73a88ee53bf1ca87 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 26 Dec 2019 18:31:47 +0100 Subject: Update doc --- src/python/doc/wasserstein_distance_user.rst | 14 +++++++++++--- src/python/gudhi/hera.cc | 8 +++++++- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/python/doc/wasserstein_distance_user.rst b/src/python/doc/wasserstein_distance_user.rst index a049cfb5..13f6f1af 100644 --- a/src/python/doc/wasserstein_distance_user.rst +++ b/src/python/doc/wasserstein_distance_user.rst @@ -9,12 +9,20 @@ Definition .. include:: wasserstein_distance_sum.inc -This implementation is based on ideas from "Large Scale Computation of Means and Cluster for Persistence Diagrams via Optimal Transport". +Functions +--------- +This implementation is based on ideas from "Large Scale Computation of Means +and Cluster for Persistence Diagrams via Optimal Transport". -Function --------- .. autofunction:: gudhi.wasserstein.wasserstein_distance +This other implementation comes from `Hera +`_ and is based on `"Geometry +Helps to Compare Persistence Diagrams." +`_ by Michael Kerber, Dmitriy +Morozov, and Arnur Nigmetov, at ALENEX 2016. + +.. autofunction:: gudhi.hera.wasserstein_distance Basic example ------------- diff --git a/src/python/gudhi/hera.cc b/src/python/gudhi/hera.cc index 7cef9425..04f5990f 100644 --- a/src/python/gudhi/hera.cc +++ b/src/python/gudhi/hera.cc @@ -42,7 +42,13 @@ double wasserstein_distance( } PYBIND11_MODULE(hera, m) { - m.def("wasserstein_distance", &wasserstein_distance, R"pbdoc( + m.def("wasserstein_distance", &wasserstein_distance, + py::arg("X"), py::arg("Y"), + R"pbdoc( Compute the Wasserstein distance between two diagrams + + Parameters: + X (n x 2 numpy array): First diagram + Y (n x 2 numpy array): Second diagram )pbdoc"); } -- cgit v1.2.3 From 003b33403ab92e25cab2b9e51b36528d5cc6112c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 26 Dec 2019 19:30:04 +0100 Subject: Check for pybind11 --- .appveyor.yml | 2 +- .travis.yml | 2 +- .../modules/GUDHI_third_party_libraries.cmake | 1 + src/python/CMakeLists.txt | 51 ++++++++++++---------- 4 files changed, 31 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/.appveyor.yml b/.appveyor.yml index 4a76ea0a..3a33ed62 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -48,7 +48,7 @@ install: - pip --version - python -m pip install --upgrade pip - pip install -U setuptools numpy matplotlib scipy Cython pytest - - pip install -U POT + - pip install -U POT pybind11 build_script: - mkdir build diff --git a/.travis.yml b/.travis.yml index d6c82e70..4b4c7068 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,7 +59,7 @@ before_cache: install: - python3 -m pip install --upgrade pip setuptools wheel - python3 -m pip install --user pytest Cython sphinx sphinxcontrib-bibtex sphinx-paramlinks matplotlib numpy scipy scikit-learn - - python3 -m pip install --user POT + - python3 -m pip install --user POT pybind11 script: - rm -rf build diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 24a34150..cb9f9033 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -127,6 +127,7 @@ if( PYTHONINTERP_FOUND ) find_python_module("sphinx") find_python_module("sklearn") find_python_module("ot") + find_python_module("pybind11") endif() if(NOT GUDHI_PYTHON_PATH) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index bec38305..edb1ba02 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -407,32 +407,37 @@ endif(CGAL_FOUND) if(SCIPY_FOUND) if(SKLEARN_FOUND) if(OT_FOUND) - if(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) - 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_PYTHON_PATH STREQUAL "src/python") - 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) + if(PYBIND11_FOUND) + if(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) + 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_PYTHON_PATH STREQUAL "src/python") + 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) + 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.11.0) - message("++ Python documentation module will not be compiled because it requires a Eigen3 and CGAL version >= 4.11.0") + # 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.11.0) + message("++ Python documentation module will not be compiled because it requires a Eigen3 and CGAL version >= 4.11.0") + set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") + endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) + else(PYBIND11_FOUND) + message("++ Python documentation module will not be compiled because pybind11 was not found") set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") - endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) + endif(PYBIND11_FOUND) else(OT_FOUND) message("++ Python documentation module will not be compiled because POT was not found") set(GUDHI_MISSING_MODULES ${GUDHI_MISSING_MODULES} "python-documentation" CACHE INTERNAL "GUDHI_MISSING_MODULES") -- cgit v1.2.3 From b8701d847db37b80a58770e00b91494889df00e8 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 27 Dec 2019 00:56:08 +0100 Subject: Expose more options --- src/python/doc/wasserstein_distance_user.rst | 4 ++-- src/python/gudhi/hera.cc | 31 +++++++++++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/python/doc/wasserstein_distance_user.rst b/src/python/doc/wasserstein_distance_user.rst index 13f6f1af..6cd7f3a0 100644 --- a/src/python/doc/wasserstein_distance_user.rst +++ b/src/python/doc/wasserstein_distance_user.rst @@ -17,8 +17,8 @@ and Cluster for Persistence Diagrams via Optimal Transport". .. autofunction:: gudhi.wasserstein.wasserstein_distance This other implementation comes from `Hera -`_ and is based on `"Geometry -Helps to Compare Persistence Diagrams." +`_ (BSD-3-Clause) and is +based on `"Geometry Helps to Compare Persistence Diagrams." `_ by Michael Kerber, Dmitriy Morozov, and Arnur Nigmetov, at ALENEX 2016. diff --git a/src/python/gudhi/hera.cc b/src/python/gudhi/hera.cc index 04f5990f..898040fb 100644 --- a/src/python/gudhi/hera.cc +++ b/src/python/gudhi/hera.cc @@ -12,7 +12,6 @@ typedef py::array_t Dgm; namespace hera { template <> struct DiagramTraits{ - //using Container = void; using PointType = std::array; using RealType = double; @@ -22,15 +21,17 @@ template <> struct DiagramTraits{ } double wasserstein_distance( - Dgm d1, - Dgm d2) + Dgm d1, Dgm d2, + double wasserstein_power, double internal_p, + double delta) { py::buffer_info buf1 = d1.request(); py::buffer_info buf2 = d2.request(); - if(buf1.ndim!=2 || buf1.shape[1]!=2) - throw std::runtime_error("Diagram 1 must be an array of size n x 2"); - if(buf2.ndim!=2 || buf2.shape[1]!=2) + // shape (n,2) or (0) for empty + if((buf1.ndim!=2 || buf1.shape[1]!=2) && (buf1.ndim!=1 || buf1.shape[0]!=0)) throw std::runtime_error("Diagram 1 must be an array of size n x 2"); + if((buf2.ndim!=2 || buf2.shape[1]!=2) && (buf2.ndim!=1 || buf2.shape[0]!=0)) + throw std::runtime_error("Diagram 2 must be an array of size n x 2"); typedef hera::DiagramTraits::PointType Point; auto p1 = (Point*)buf1.ptr; auto p2 = (Point*)buf2.ptr; @@ -38,17 +39,33 @@ double wasserstein_distance( auto diag2 = boost::make_iterator_range(p2, p2+buf2.shape[0]); hera::AuctionParams params; + params.wasserstein_power = wasserstein_power; + // hera encodes infinity as -1... + if(std::isinf(internal_p)) internal_p = hera::get_infinity(); + params.internal_p = internal_p; + params.delta = delta; + // The extra parameters are purposedly not exposed for now. return hera::wasserstein_dist(diag1, diag2, params); } PYBIND11_MODULE(hera, m) { m.def("wasserstein_distance", &wasserstein_distance, py::arg("X"), py::arg("Y"), + // Should we name those q, p and d instead? + py::arg("wasserstein_power") = 1, + py::arg("internal_p") = std::numeric_limits::infinity(), + py::arg("delta") = .01, R"pbdoc( - Compute the Wasserstein distance between two diagrams + Compute the Wasserstein distance between two diagrams. Points at infinity are supported. Parameters: X (n x 2 numpy array): First diagram Y (n x 2 numpy array): Second diagram + wasserstein_power (float): Wasserstein degree W_q + internal_p (float): Internal Minkowski norm L^p in R^2 + delta (float): Relative error 1+delta + + Returns: + float: Approximate Wasserstein distance W_q(X,Y) )pbdoc"); } -- cgit v1.2.3 From a7f3167ffb465bd6d1e3b9e40bc6f1c35daf87fc Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 20 Jan 2020 16:43:37 +0100 Subject: Simplify the pybind11 code --- src/python/doc/wasserstein_distance_user.rst | 5 +++-- src/python/gudhi/hera.cc | 19 +++++-------------- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/python/doc/wasserstein_distance_user.rst b/src/python/doc/wasserstein_distance_user.rst index 6cd7f3a0..355ad247 100644 --- a/src/python/doc/wasserstein_distance_user.rst +++ b/src/python/doc/wasserstein_distance_user.rst @@ -11,8 +11,9 @@ Definition Functions --------- -This implementation is based on ideas from "Large Scale Computation of Means -and Cluster for Persistence Diagrams via Optimal Transport". +This implementation uses the Python Optimal Transport library and is based on +ideas from "Large Scale Computation of Means and Cluster for Persistence +Diagrams via Optimal Transport". .. autofunction:: gudhi.wasserstein.wasserstein_distance diff --git a/src/python/gudhi/hera.cc b/src/python/gudhi/hera.cc index 898040fb..61f0da10 100644 --- a/src/python/gudhi/hera.cc +++ b/src/python/gudhi/hera.cc @@ -10,16 +10,6 @@ namespace py = pybind11; typedef py::array_t Dgm; -namespace hera { -template <> struct DiagramTraits{ - using PointType = std::array; - using RealType = double; - - static RealType get_x(const PointType& p) { return std::get<0>(p); } - static RealType get_y(const PointType& p) { return std::get<1>(p); } -}; -} - double wasserstein_distance( Dgm d1, Dgm d2, double wasserstein_power, double internal_p, @@ -32,7 +22,7 @@ double wasserstein_distance( throw std::runtime_error("Diagram 1 must be an array of size n x 2"); if((buf2.ndim!=2 || buf2.shape[1]!=2) && (buf2.ndim!=1 || buf2.shape[0]!=0)) throw std::runtime_error("Diagram 2 must be an array of size n x 2"); - typedef hera::DiagramTraits::PointType Point; + typedef std::array Point; auto p1 = (Point*)buf1.ptr; auto p2 = (Point*)buf2.ptr; auto diag1 = boost::make_iterator_range(p1, p1+buf1.shape[0]); @@ -52,16 +42,17 @@ PYBIND11_MODULE(hera, m) { m.def("wasserstein_distance", &wasserstein_distance, py::arg("X"), py::arg("Y"), // Should we name those q, p and d instead? - py::arg("wasserstein_power") = 1, + py::arg("order") = 1, py::arg("internal_p") = std::numeric_limits::infinity(), py::arg("delta") = .01, R"pbdoc( - Compute the Wasserstein distance between two diagrams. Points at infinity are supported. + Compute the Wasserstein distance between two diagrams. + Points at infinity are supported. Parameters: X (n x 2 numpy array): First diagram Y (n x 2 numpy array): Second diagram - wasserstein_power (float): Wasserstein degree W_q + order (float): Wasserstein exponent W_q internal_p (float): Internal Minkowski norm L^p in R^2 delta (float): Relative error 1+delta -- cgit v1.2.3 From 1783c047302414bbcd6ff4f7c73dcc5a6501fd81 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 20 Jan 2020 17:51:28 +0100 Subject: Share tests for wasserstein_distance --- src/python/test/test_wasserstein_distance.py | 59 ++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/python/test/test_wasserstein_distance.py b/src/python/test/test_wasserstein_distance.py index 43dda77e..46a7079f 100755 --- a/src/python/test/test_wasserstein_distance.py +++ b/src/python/test/test_wasserstein_distance.py @@ -8,41 +8,66 @@ - YYYY/MM Author: Description of the modification """ -from gudhi.wasserstein import wasserstein_distance +from gudhi.wasserstein import wasserstein_distance as pot +from gudhi.hera import wasserstein_distance as hera import numpy as np __author__ = "Theo Lacombe" __copyright__ = "Copyright (C) 2019 Inria" __license__ = "MIT" - -def test_basic_wasserstein(): +def _basic_wasserstein(wasserstein_distance, delta, test_infinity=True): diag1 = np.array([[2.7, 3.7], [9.6, 14.0], [34.2, 34.974]]) diag2 = np.array([[2.8, 4.45], [9.5, 14.1]]) diag3 = np.array([[0, 2], [4, 6]]) diag4 = np.array([[0, 3], [4, 8]]) - emptydiag = np.array([[]]) + emptydiag = np.array([]) + + # We just need to handle positive numbers here + def approx(a, b): + f = 1 + delta + return a <= b*f and b <= a*f assert wasserstein_distance(emptydiag, emptydiag, internal_p=2., order=1.) == 0. assert wasserstein_distance(emptydiag, emptydiag, internal_p=np.inf, order=1.) == 0. assert wasserstein_distance(emptydiag, emptydiag, internal_p=np.inf, order=2.) == 0. assert wasserstein_distance(emptydiag, emptydiag, internal_p=2., order=2.) == 0. - assert wasserstein_distance(diag3, emptydiag, internal_p=np.inf, order=1.) == 2. - assert wasserstein_distance(diag3, emptydiag, internal_p=1., order=1.) == 4. + assert approx(wasserstein_distance(diag3, emptydiag, internal_p=np.inf, order=1.), 2.) + assert approx(wasserstein_distance(diag3, emptydiag, internal_p=1., order=1.), 4.) + + assert approx(wasserstein_distance(diag4, emptydiag, internal_p=1., order=2.), 5.) # thank you Pythagorician triplets + assert approx(wasserstein_distance(diag4, emptydiag, internal_p=np.inf, order=2.), 2.5) + assert approx(wasserstein_distance(diag4, emptydiag, internal_p=2., order=2.), 3.5355339059327378) + + assert approx(wasserstein_distance(diag1, diag2, internal_p=2., order=1.) , 1.4453593023967701) + assert approx(wasserstein_distance(diag1, diag2, internal_p=2.35, order=1.74), 0.9772734057168739) + + assert approx(wasserstein_distance(diag1, emptydiag, internal_p=2.35, order=1.7863), 3.141592214572228) + + assert approx(wasserstein_distance(diag3, diag4, internal_p=1., order=1.), 3.) + assert approx(wasserstein_distance(diag3, diag4, internal_p=np.inf, order=1.), 3.) # no diag matching here + assert approx(wasserstein_distance(diag3, diag4, internal_p=np.inf, order=2.), np.sqrt(5)) + assert approx(wasserstein_distance(diag3, diag4, internal_p=1., order=2.), np.sqrt(5)) + assert approx(wasserstein_distance(diag3, diag4, internal_p=4.5, order=2.), np.sqrt(5)) + + if(not test_infinity): + return - assert wasserstein_distance(diag4, emptydiag, internal_p=1., order=2.) == 5. # thank you Pythagorician triplets - assert wasserstein_distance(diag4, emptydiag, internal_p=np.inf, order=2.) == 2.5 - assert wasserstein_distance(diag4, emptydiag, internal_p=2., order=2.) == 3.5355339059327378 + diag5 = np.array([[0, 3], [4, np.inf]]) + diag6 = np.array([[7, 8], [4, 6], [3, np.inf]]) - assert wasserstein_distance(diag1, diag2, internal_p=2., order=1.) == 1.4453593023967701 - assert wasserstein_distance(diag1, diag2, internal_p=2.35, order=1.74) == 0.9772734057168739 + assert wasserstein_distance(diag4, diag5) == np.inf + assert approx(wasserstein_distance(diag5, diag6, order=1, internal_p=np.inf), 4.) - assert wasserstein_distance(diag1, emptydiag, internal_p=2.35, order=1.7863) == 3.141592214572228 +def hera_wrap(delta): + def fun(*kargs,**kwargs): + return hera(*kargs,**kwargs,delta=delta) + return fun - assert wasserstein_distance(diag3, diag4, internal_p=1., order=1.) == 3. - assert wasserstein_distance(diag3, diag4, internal_p=np.inf, order=1.) == 3. # no diag matching here - assert wasserstein_distance(diag3, diag4, internal_p=np.inf, order=2.) == np.sqrt(5) - assert wasserstein_distance(diag3, diag4, internal_p=1., order=2.) == np.sqrt(5) - assert wasserstein_distance(diag3, diag4, internal_p=4.5, order=2.) == np.sqrt(5) +def test_wasserstein_distance_pot(): + _basic_wasserstein(pot, 1e-15, False) +def test_wasserstein_distance_hera(): + _basic_wasserstein(hera_wrap(1e-12), 1e-12) + _basic_wasserstein(hera_wrap(.1), .1) -- cgit v1.2.3 From a20fdcaf9bf23f88cba2a2c5906d515fd785dc8a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 24 Jan 2020 12:15:14 +0100 Subject: Modern cmake for boost approach --- src/Alpha_complex/utilities/CMakeLists.txt | 4 ++-- src/Bottleneck_distance/example/CMakeLists.txt | 2 +- src/Cech_complex/benchmark/CMakeLists.txt | 2 +- src/Cech_complex/example/CMakeLists.txt | 2 +- src/Cech_complex/utilities/CMakeLists.txt | 2 +- src/Contraction/example/CMakeLists.txt | 2 +- src/Persistent_cohomology/benchmark/CMakeLists.txt | 2 +- src/Persistent_cohomology/example/CMakeLists.txt | 8 ++++---- src/Rips_complex/utilities/CMakeLists.txt | 8 ++++---- src/Simplex_tree/example/CMakeLists.txt | 2 +- src/Witness_complex/utilities/CMakeLists.txt | 4 ++-- src/cmake/modules/GUDHI_boost_test.cmake | 2 +- src/cmake/modules/GUDHI_third_party_libraries.cmake | 6 +++--- 13 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/Alpha_complex/utilities/CMakeLists.txt b/src/Alpha_complex/utilities/CMakeLists.txt index 57b92942..a3b0cc24 100644 --- a/src/Alpha_complex/utilities/CMakeLists.txt +++ b/src/Alpha_complex/utilities/CMakeLists.txt @@ -2,7 +2,7 @@ project(Alpha_complex_utilities) if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) add_executable (alpha_complex_persistence alpha_complex_persistence.cpp) - target_link_libraries(alpha_complex_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) + target_link_libraries(alpha_complex_persistence ${CGAL_LIBRARY} Boost::program_options) if (TBB_FOUND) target_link_libraries(alpha_complex_persistence ${TBB_LIBRARIES}) @@ -23,7 +23,7 @@ if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) install(TARGETS alpha_complex_persistence DESTINATION bin) add_executable(alpha_complex_3d_persistence alpha_complex_3d_persistence.cpp) - target_link_libraries(alpha_complex_3d_persistence ${CGAL_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) + target_link_libraries(alpha_complex_3d_persistence ${CGAL_LIBRARY} Boost::program_options) if (TBB_FOUND) target_link_libraries(alpha_complex_3d_persistence ${TBB_LIBRARIES}) endif(TBB_FOUND) diff --git a/src/Bottleneck_distance/example/CMakeLists.txt b/src/Bottleneck_distance/example/CMakeLists.txt index 3d65963a..9839c59d 100644 --- a/src/Bottleneck_distance/example/CMakeLists.txt +++ b/src/Bottleneck_distance/example/CMakeLists.txt @@ -13,7 +13,7 @@ endif (NOT CGAL_VERSION VERSION_LESS 4.11.0) if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) add_executable (alpha_rips_persistence_bottleneck_distance alpha_rips_persistence_bottleneck_distance.cpp) - target_link_libraries(alpha_rips_persistence_bottleneck_distance ${Boost_PROGRAM_OPTIONS_LIBRARY}) + target_link_libraries(alpha_rips_persistence_bottleneck_distance Boost::program_options) if (TBB_FOUND) target_link_libraries(alpha_rips_persistence_bottleneck_distance ${TBB_LIBRARIES}) diff --git a/src/Cech_complex/benchmark/CMakeLists.txt b/src/Cech_complex/benchmark/CMakeLists.txt index b7697764..c04bca53 100644 --- a/src/Cech_complex/benchmark/CMakeLists.txt +++ b/src/Cech_complex/benchmark/CMakeLists.txt @@ -5,7 +5,7 @@ project(Cech_complex_benchmark) file(COPY "${CMAKE_SOURCE_DIR}/data/points/tore3D_1307.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) add_executable(cech_complex_benchmark cech_complex_benchmark.cpp) -target_link_libraries(cech_complex_benchmark ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) +target_link_libraries(cech_complex_benchmark Boost::filesystem) if (TBB_FOUND) target_link_libraries(cech_complex_benchmark ${TBB_LIBRARIES}) diff --git a/src/Cech_complex/example/CMakeLists.txt b/src/Cech_complex/example/CMakeLists.txt index ab391215..98757988 100644 --- a/src/Cech_complex/example/CMakeLists.txt +++ b/src/Cech_complex/example/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) project(Cech_complex_examples) add_executable ( Cech_complex_example_step_by_step cech_complex_step_by_step.cpp ) -target_link_libraries(Cech_complex_example_step_by_step ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(Cech_complex_example_step_by_step Boost::program_options) if (TBB_FOUND) target_link_libraries(Cech_complex_example_step_by_step ${TBB_LIBRARIES}) endif() diff --git a/src/Cech_complex/utilities/CMakeLists.txt b/src/Cech_complex/utilities/CMakeLists.txt index 30b99729..253d7304 100644 --- a/src/Cech_complex/utilities/CMakeLists.txt +++ b/src/Cech_complex/utilities/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) project(Cech_complex_utilities) add_executable(cech_persistence cech_persistence.cpp) -target_link_libraries(cech_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(cech_persistence Boost::program_options) if (TBB_FOUND) target_link_libraries(cech_persistence ${TBB_LIBRARIES}) diff --git a/src/Contraction/example/CMakeLists.txt b/src/Contraction/example/CMakeLists.txt index f0dc885d..4740a2d1 100644 --- a/src/Contraction/example/CMakeLists.txt +++ b/src/Contraction/example/CMakeLists.txt @@ -4,7 +4,7 @@ if (NOT CGAL_VERSION VERSION_LESS 4.11.0) add_executable(RipsContraction Rips_contraction.cpp) add_executable(GarlandHeckbert Garland_heckbert.cpp) - target_link_libraries(GarlandHeckbert ${Boost_TIMER_LIBRARY}) + target_link_libraries(GarlandHeckbert Boost::timer) add_test(NAME Contraction_example_tore3D_0.2 COMMAND $ "${CMAKE_SOURCE_DIR}/data/points/tore3D_1307.off" "0.2") diff --git a/src/Persistent_cohomology/benchmark/CMakeLists.txt b/src/Persistent_cohomology/benchmark/CMakeLists.txt index 2bb3b0c7..f38cc543 100644 --- a/src/Persistent_cohomology/benchmark/CMakeLists.txt +++ b/src/Persistent_cohomology/benchmark/CMakeLists.txt @@ -3,7 +3,7 @@ project(Persistent_cohomology_benchmark) if(GMP_FOUND) if(GMPXX_FOUND) add_executable ( performance_rips_persistence EXCLUDE_FROM_ALL performance_rips_persistence.cpp ) - target_link_libraries(performance_rips_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) + target_link_libraries(performance_rips_persistence Boost::program_options ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) if (TBB_FOUND) target_link_libraries(performance_rips_persistence ${TBB_LIBRARIES}) endif(TBB_FOUND) diff --git a/src/Persistent_cohomology/example/CMakeLists.txt b/src/Persistent_cohomology/example/CMakeLists.txt index 94ec13c5..4c08cd68 100644 --- a/src/Persistent_cohomology/example/CMakeLists.txt +++ b/src/Persistent_cohomology/example/CMakeLists.txt @@ -5,13 +5,13 @@ add_executable(plain_homology plain_homology.cpp) add_executable(persistence_from_simple_simplex_tree persistence_from_simple_simplex_tree.cpp) add_executable(rips_persistence_step_by_step rips_persistence_step_by_step.cpp) -target_link_libraries(rips_persistence_step_by_step ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(rips_persistence_step_by_step Boost::program_options) add_executable(rips_persistence_via_boundary_matrix rips_persistence_via_boundary_matrix.cpp) -target_link_libraries(rips_persistence_via_boundary_matrix ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(rips_persistence_via_boundary_matrix Boost::program_options) add_executable(persistence_from_file persistence_from_file.cpp) -target_link_libraries(persistence_from_file ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(persistence_from_file Boost::program_options) if (TBB_FOUND) target_link_libraries(plain_homology ${TBB_LIBRARIES}) @@ -43,7 +43,7 @@ if(GMP_FOUND) if(GMPXX_FOUND) add_executable(rips_multifield_persistence rips_multifield_persistence.cpp ) target_link_libraries(rips_multifield_persistence - ${Boost_PROGRAM_OPTIONS_LIBRARY} ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) + Boost::program_options ${GMPXX_LIBRARIES} ${GMP_LIBRARIES}) if (TBB_FOUND) target_link_libraries(rips_multifield_persistence ${TBB_LIBRARIES}) endif(TBB_FOUND) diff --git a/src/Rips_complex/utilities/CMakeLists.txt b/src/Rips_complex/utilities/CMakeLists.txt index 4b565628..d2448d7b 100644 --- a/src/Rips_complex/utilities/CMakeLists.txt +++ b/src/Rips_complex/utilities/CMakeLists.txt @@ -1,16 +1,16 @@ project(Rips_complex_utilities) add_executable(rips_distance_matrix_persistence rips_distance_matrix_persistence.cpp) -target_link_libraries(rips_distance_matrix_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(rips_distance_matrix_persistence Boost::program_options) add_executable(rips_persistence rips_persistence.cpp) -target_link_libraries(rips_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(rips_persistence Boost::program_options) add_executable(rips_correlation_matrix_persistence rips_correlation_matrix_persistence.cpp) -target_link_libraries(rips_correlation_matrix_persistence ${Boost_SYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(rips_correlation_matrix_persistence Boost::system Boost::program_options) add_executable(sparse_rips_persistence sparse_rips_persistence.cpp) -target_link_libraries(sparse_rips_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY}) +target_link_libraries(sparse_rips_persistence Boost::program_options) if (TBB_FOUND) target_link_libraries(rips_distance_matrix_persistence ${TBB_LIBRARIES}) diff --git a/src/Simplex_tree/example/CMakeLists.txt b/src/Simplex_tree/example/CMakeLists.txt index f99b164c..6ba518fa 100644 --- a/src/Simplex_tree/example/CMakeLists.txt +++ b/src/Simplex_tree/example/CMakeLists.txt @@ -32,7 +32,7 @@ endif() if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) add_executable ( Simplex_tree_example_cech_complex_cgal_mini_sphere_3d cech_complex_cgal_mini_sphere_3d.cpp ) - target_link_libraries(Simplex_tree_example_cech_complex_cgal_mini_sphere_3d ${Boost_PROGRAM_OPTIONS_LIBRARY} ${CGAL_LIBRARY}) + target_link_libraries(Simplex_tree_example_cech_complex_cgal_mini_sphere_3d Boost::program_options ${CGAL_LIBRARY}) if (TBB_FOUND) target_link_libraries(Simplex_tree_example_cech_complex_cgal_mini_sphere_3d ${TBB_LIBRARIES}) endif() diff --git a/src/Witness_complex/utilities/CMakeLists.txt b/src/Witness_complex/utilities/CMakeLists.txt index 3ee0c2f6..d986d2d1 100644 --- a/src/Witness_complex/utilities/CMakeLists.txt +++ b/src/Witness_complex/utilities/CMakeLists.txt @@ -4,10 +4,10 @@ project(Witness_complex_utilities) if(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.11.0) add_executable ( Witness_complex_strong_witness_persistence strong_witness_persistence.cpp ) - target_link_libraries(Witness_complex_strong_witness_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY}) + target_link_libraries(Witness_complex_strong_witness_persistence Boost::program_options) add_executable ( Witness_complex_weak_witness_persistence weak_witness_persistence.cpp ) - target_link_libraries(Witness_complex_weak_witness_persistence ${Boost_PROGRAM_OPTIONS_LIBRARY}) + target_link_libraries(Witness_complex_weak_witness_persistence Boost::program_options) if (TBB_FOUND) target_link_libraries(Witness_complex_strong_witness_persistence ${TBB_LIBRARIES}) diff --git a/src/cmake/modules/GUDHI_boost_test.cmake b/src/cmake/modules/GUDHI_boost_test.cmake index c3b29883..3b9da78f 100644 --- a/src/cmake/modules/GUDHI_boost_test.cmake +++ b/src/cmake/modules/GUDHI_boost_test.cmake @@ -19,7 +19,7 @@ else (WITH_GUDHI_BOOST_TEST_COVERAGE) endif(WITH_GUDHI_BOOST_TEST_COVERAGE) function(gudhi_add_boost_test unitary_test) - target_link_libraries(${unitary_test} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) + target_link_libraries(${unitary_test} Boost::unit_test_framework) add_test(NAME ${unitary_test} COMMAND $ ${GUDHI_UT_LOG_FORMAT} ${GUDHI_UT_LOG_SINK} ${GUDHI_UT_LOG_LEVEL} ${GUDHI_UT_REPORT_LEVEL}) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 24a34150..4d121eca 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -1,6 +1,6 @@ # This files manage third party libraries required by GUDHI -find_package(Boost 1.56.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread) +find_package(Boost 1.56.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread timer) if(NOT Boost_FOUND) message(FATAL_ERROR "NOTICE: This program requires Boost and will not be compiled.") @@ -82,8 +82,8 @@ add_definitions( -DBOOST_ALL_DYN_LINK ) # problem on Mac with boost_system and boost_thread add_definitions( -DBOOST_SYSTEM_NO_DEPRECATED ) -INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) -LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) +#INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) +#LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) message(STATUS "boost include dirs:" ${Boost_INCLUDE_DIRS}) message(STATUS "boost library dirs:" ${Boost_LIBRARY_DIRS}) -- cgit v1.2.3 From a604e92c73d4f83281dd62e180a9ec6a70d3bd00 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 24 Jan 2020 14:26:40 +0100 Subject: Remove boost timer as not used --- src/Contraction/example/CMakeLists.txt | 1 - src/cmake/modules/GUDHI_third_party_libraries.cmake | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/Contraction/example/CMakeLists.txt b/src/Contraction/example/CMakeLists.txt index 4740a2d1..c5d31aca 100644 --- a/src/Contraction/example/CMakeLists.txt +++ b/src/Contraction/example/CMakeLists.txt @@ -4,7 +4,6 @@ if (NOT CGAL_VERSION VERSION_LESS 4.11.0) add_executable(RipsContraction Rips_contraction.cpp) add_executable(GarlandHeckbert Garland_heckbert.cpp) - target_link_libraries(GarlandHeckbert Boost::timer) add_test(NAME Contraction_example_tore3D_0.2 COMMAND $ "${CMAKE_SOURCE_DIR}/data/points/tore3D_1307.off" "0.2") diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 4d121eca..10b2b56a 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -1,6 +1,6 @@ # This files manage third party libraries required by GUDHI -find_package(Boost 1.56.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread timer) +find_package(Boost 1.56.0 REQUIRED COMPONENTS system filesystem unit_test_framework program_options thread) if(NOT Boost_FOUND) message(FATAL_ERROR "NOTICE: This program requires Boost and will not be compiled.") -- cgit v1.2.3 From 22c946ecc9594fc496d641b70a19643057295dcf Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 24 Jan 2020 15:48:16 +0100 Subject: Accordingly to the documentation, cmake 3.5 is required for modern boost finding --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dcc6803..a9f7f989 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(GUDHIdev) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 561aa049..0e799a3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(GUDHI) -- cgit v1.2.3 From 48952ee2ad76e2f4e5ada7f038ff88dee496272a Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 30 Jan 2020 11:58:52 +0100 Subject: Allow use of preinstalled Hera --- src/cmake/modules/GUDHI_third_party_libraries.cmake | 3 +++ src/python/setup.py.in | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index cb9f9033..359d1c12 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -35,6 +35,9 @@ if(CGAL_FOUND) include( ${CGAL_USE_FILE} ) endif() +# For those who dislike bundled dependencies, this indicates where to find a preinstalled Hera. +set(HERA_WASSERSTEIN_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/ext/hera/geom_matching/wasserstein/include CACHE PATH "Directory where one can find Hera's wasserstein.h") + option(WITH_GUDHI_USE_TBB "Build with Intel TBB parallelization" ON) # Find TBB package for parallel sort - not mandatory, just optional. diff --git a/src/python/setup.py.in b/src/python/setup.py.in index 08c46ced..851188bd 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -63,7 +63,7 @@ ext_modules.append(Extension( sources = [source_dir + 'hera.cc'], language = 'c++', include_dirs = include_dirs + - ['@CMAKE_SOURCE_DIR@/ext/hera/geom_matching/wasserstein/include', + ['@HERA_WASSERSTEIN_INCLUDE_DIR@', get_pybind_include(False), get_pybind_include(True)], extra_compile_args=extra_compile_args + [@GUDHI_PYBIND11_EXTRA_COMPILE_ARGS@], )) -- cgit v1.2.3 From 09cf8752c50f25acac0eb1a6369624399431b2ca Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 30 Jan 2020 12:14:20 +0100 Subject: Document dependency on pybind11 --- src/python/doc/installation.rst | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index 40f3f44b..f8456799 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -257,6 +257,14 @@ The :doc:`Wasserstein distance ` module requires `POT `_, a library that provides several solvers for optimization problems related to Optimal Transport. +Pybind11 +======== + +The :doc:`Wasserstein distance ` module requires +`pybind11 `_, a library that provides +interoperability between C++ and Python, for its interface to `Hera +`_. + Scikit-learn ============ -- cgit v1.2.3 From 966a8e0131cb55d815bfe6c8286c9d7865f1a32f Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 5 Feb 2020 16:09:45 +0100 Subject: Add gudhi.representations in setup.py packages --- src/python/setup.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/setup.py.in b/src/python/setup.py.in index 9c2124f4..f993165c 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -44,7 +44,7 @@ for module in modules: setup( name = 'gudhi', - packages=["gudhi",], + packages=["gudhi","gudhi.representations"], author='GUDHI Editorial Board', author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', -- cgit v1.2.3 From 00c46d21df80c51a0c83e412230f4583a5803fc9 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 6 Feb 2020 19:27:36 +0100 Subject: Print pybind11 version, protect test --- src/python/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index edb1ba02..090a7446 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -32,6 +32,10 @@ function( add_gudhi_debug_info DEBUG_INFO ) endfunction( add_gudhi_debug_info ) if(PYTHONINTERP_FOUND) + if(PYBIND11_FOUND) + add_gudhi_debug_info("Pybind11 version ${PYBIND11_VERSION}") + set(GUDHI_PYTHON_MODULES_EXTRA "${GUDHI_PYTHON_MODULES_EXTRA}'hera', ") + endif() if(CYTHON_FOUND) set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'off_reader', ") set(GUDHI_PYTHON_MODULES "${GUDHI_PYTHON_MODULES}'simplex_tree', ") @@ -391,9 +395,9 @@ endif(CGAL_FOUND) add_gudhi_py_test(test_reader_utils) # Wasserstein - if(OT_FOUND) + if(OT_FOUND AND PYBIND11_FOUND) add_gudhi_py_test(test_wasserstein_distance) - endif(OT_FOUND) + endif() # Representations if(SKLEARN_FOUND AND MATPLOTLIB_FOUND) -- cgit v1.2.3 From 08b82e8a606a7fcd1219e7074cc2f15340090e59 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 6 Feb 2020 21:20:17 +0100 Subject: Make pybind11 mandatory and simplify The use of install_requires and setup_requires looks strange, I would expect cython in setup_requires, not install_requires. But setup_requires doesn't seem to work so well anyway. --- src/python/doc/installation.rst | 13 +++---------- src/python/setup.py.in | 19 +++---------------- 2 files changed, 6 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index f8456799..d459145b 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -14,10 +14,11 @@ Compiling ********* The library uses c++14 and requires `Boost `_ ≥ 1.56.0, `CMake `_ ≥ 3.1 to generate makefiles, -`NumPy `_ and `Cython `_ to compile +`NumPy `_, `Cython `_ and +`pybind11 `_ to compile the GUDHI Python module. It is a multi-platform library and compiles on Linux, Mac OSX and Visual -Studio 2015. +Studio 2017. On `Windows `_ , only Python ≥ 3.5 are available because of the required Visual Studio version. @@ -257,14 +258,6 @@ The :doc:`Wasserstein distance ` module requires `POT `_, a library that provides several solvers for optimization problems related to Optimal Transport. -Pybind11 -======== - -The :doc:`Wasserstein distance ` module requires -`pybind11 `_, a library that provides -interoperability between C++ and Python, for its interface to `Hera -`_. - Scikit-learn ============ diff --git a/src/python/setup.py.in b/src/python/setup.py.in index 851188bd..d05e4675 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -12,6 +12,7 @@ from setuptools import setup, Extension from Cython.Build import cythonize from numpy import get_include as numpy_get_include import sys +import pybind11 __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" @@ -27,20 +28,6 @@ library_dirs=[@GUDHI_PYTHON_LIBRARY_DIRS@] include_dirs = [numpy_get_include(), '@CMAKE_CURRENT_SOURCE_DIR@/gudhi/', @GUDHI_PYTHON_INCLUDE_DIRS@] runtime_library_dirs=[@GUDHI_PYTHON_RUNTIME_LIBRARY_DIRS@] -# Copied from https://github.com/pybind/python_example/blob/master/setup.py -class get_pybind_include(object): - """Helper class to determine the pybind11 include path - The purpose of this class is to postpone importing pybind11 - until it is actually installed, so that the ``get_include()`` - method can be invoked. """ - - def __init__(self, user=False): - self.user = user - - def __str__(self): - import pybind11 - return pybind11.get_include(self.user) - # Create ext_modules list from module list ext_modules = [] for module in modules: @@ -64,7 +51,7 @@ ext_modules.append(Extension( language = 'c++', include_dirs = include_dirs + ['@HERA_WASSERSTEIN_INCLUDE_DIR@', - get_pybind_include(False), get_pybind_include(True)], + pybind11.get_include(False), pybind11.get_include(True)], extra_compile_args=extra_compile_args + [@GUDHI_PYBIND11_EXTRA_COMPILE_ARGS@], )) @@ -76,6 +63,6 @@ setup( version='@GUDHI_VERSION@', url='http://gudhi.gforge.inria.fr/', ext_modules = ext_modules, - install_requires = ['cython','numpy >= 1.9','pybind11',], + install_requires = ['cython','numpy >= 1.9',], setup_requires = ['numpy >= 1.9','pybind11',], ) -- cgit v1.2.3 From 518c619d578dc6f168b6369417f15872e3cd0056 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 6 Feb 2020 21:54:44 +0100 Subject: use bibtex --- biblio/bibliography.bib | 12 ++++++++++++ src/python/doc/wasserstein_distance_user.rst | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/biblio/bibliography.bib b/biblio/bibliography.bib index a1b951e0..3bbe7960 100644 --- a/biblio/bibliography.bib +++ b/biblio/bibliography.bib @@ -1180,3 +1180,15 @@ language={English} booktitle = {In Neural Information Processing Systems}, year = {2007} } +@inproceedings{10.5555/3327546.3327645, +author = {Lacombe, Th\'{e}o and Cuturi, Marco and Oudot, Steve}, +title = {Large Scale Computation of Means and Clusters for Persistence Diagrams Using Optimal Transport}, +year = {2018}, +publisher = {Curran Associates Inc.}, +address = {Red Hook, NY, USA}, +booktitle = {Proceedings of the 32nd International Conference on Neural Information Processing Systems}, +pages = {9792–9802}, +numpages = {11}, +location = {Montr\'{e}al, Canada}, +series = {NIPS’18} +} diff --git a/src/python/doc/wasserstein_distance_user.rst b/src/python/doc/wasserstein_distance_user.rst index 648cc568..99445b99 100644 --- a/src/python/doc/wasserstein_distance_user.rst +++ b/src/python/doc/wasserstein_distance_user.rst @@ -13,15 +13,15 @@ Functions --------- This implementation uses the Python Optimal Transport library and is based on ideas from "Large Scale Computation of Means and Cluster for Persistence -Diagrams via Optimal Transport". +Diagrams via Optimal Transport" :cite:`10.5555/3327546.3327645`. .. autofunction:: gudhi.wasserstein.wasserstein_distance This other implementation comes from `Hera -`_ (BSD-3-Clause) and is -based on `"Geometry Helps to Compare Persistence Diagrams." -`_ by Michael Kerber, Dmitriy -Morozov, and Arnur Nigmetov, at ALENEX 2016. +`_ (BSD-3-Clause) which is +based on "Geometry Helps to Compare Persistence Diagrams" +:cite:`Kerber:2017:GHC:3047249.3064175` by Michael Kerber, Dmitriy +Morozov, and Arnur Nigmetov. .. autofunction:: gudhi.hera.wasserstein_distance -- cgit v1.2.3 From e8c908469cb4ac547d4fd46ad8daf5ee21739f58 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 6 Feb 2020 22:14:08 +0100 Subject: pytest.approx --- src/python/test/test_wasserstein_distance.py | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/python/test/test_wasserstein_distance.py b/src/python/test/test_wasserstein_distance.py index 46a7079f..6a14c50e 100755 --- a/src/python/test/test_wasserstein_distance.py +++ b/src/python/test/test_wasserstein_distance.py @@ -11,6 +11,7 @@ from gudhi.wasserstein import wasserstein_distance as pot from gudhi.hera import wasserstein_distance as hera import numpy as np +import pytest __author__ = "Theo Lacombe" __copyright__ = "Copyright (C) 2019 Inria" @@ -24,32 +25,31 @@ def _basic_wasserstein(wasserstein_distance, delta, test_infinity=True): emptydiag = np.array([]) # We just need to handle positive numbers here - def approx(a, b): - f = 1 + delta - return a <= b*f and b <= a*f + def approx(x): + return pytest.approx(x, rel=delta) assert wasserstein_distance(emptydiag, emptydiag, internal_p=2., order=1.) == 0. assert wasserstein_distance(emptydiag, emptydiag, internal_p=np.inf, order=1.) == 0. assert wasserstein_distance(emptydiag, emptydiag, internal_p=np.inf, order=2.) == 0. assert wasserstein_distance(emptydiag, emptydiag, internal_p=2., order=2.) == 0. - assert approx(wasserstein_distance(diag3, emptydiag, internal_p=np.inf, order=1.), 2.) - assert approx(wasserstein_distance(diag3, emptydiag, internal_p=1., order=1.), 4.) + assert wasserstein_distance(diag3, emptydiag, internal_p=np.inf, order=1.) == approx(2.) + assert wasserstein_distance(diag3, emptydiag, internal_p=1., order=1.) == approx(4.) - assert approx(wasserstein_distance(diag4, emptydiag, internal_p=1., order=2.), 5.) # thank you Pythagorician triplets - assert approx(wasserstein_distance(diag4, emptydiag, internal_p=np.inf, order=2.), 2.5) - assert approx(wasserstein_distance(diag4, emptydiag, internal_p=2., order=2.), 3.5355339059327378) + assert wasserstein_distance(diag4, emptydiag, internal_p=1., order=2.) == approx(5.) # thank you Pythagorician triplets + assert wasserstein_distance(diag4, emptydiag, internal_p=np.inf, order=2.) == approx(2.5) + assert wasserstein_distance(diag4, emptydiag, internal_p=2., order=2.) == approx(3.5355339059327378) - assert approx(wasserstein_distance(diag1, diag2, internal_p=2., order=1.) , 1.4453593023967701) - assert approx(wasserstein_distance(diag1, diag2, internal_p=2.35, order=1.74), 0.9772734057168739) + assert wasserstein_distance(diag1, diag2, internal_p=2., order=1.) == approx(1.4453593023967701) + assert wasserstein_distance(diag1, diag2, internal_p=2.35, order=1.74) == approx(0.9772734057168739) - assert approx(wasserstein_distance(diag1, emptydiag, internal_p=2.35, order=1.7863), 3.141592214572228) + assert wasserstein_distance(diag1, emptydiag, internal_p=2.35, order=1.7863) == approx(3.141592214572228) - assert approx(wasserstein_distance(diag3, diag4, internal_p=1., order=1.), 3.) - assert approx(wasserstein_distance(diag3, diag4, internal_p=np.inf, order=1.), 3.) # no diag matching here - assert approx(wasserstein_distance(diag3, diag4, internal_p=np.inf, order=2.), np.sqrt(5)) - assert approx(wasserstein_distance(diag3, diag4, internal_p=1., order=2.), np.sqrt(5)) - assert approx(wasserstein_distance(diag3, diag4, internal_p=4.5, order=2.), np.sqrt(5)) + assert wasserstein_distance(diag3, diag4, internal_p=1., order=1.) == approx(3.) + assert wasserstein_distance(diag3, diag4, internal_p=np.inf, order=1.) == approx(3.) # no diag matching here + assert wasserstein_distance(diag3, diag4, internal_p=np.inf, order=2.) == approx(np.sqrt(5)) + assert wasserstein_distance(diag3, diag4, internal_p=1., order=2.) == approx(np.sqrt(5)) + assert wasserstein_distance(diag3, diag4, internal_p=4.5, order=2.) == approx(np.sqrt(5)) if(not test_infinity): return @@ -58,7 +58,7 @@ def _basic_wasserstein(wasserstein_distance, delta, test_infinity=True): diag6 = np.array([[7, 8], [4, 6], [3, np.inf]]) assert wasserstein_distance(diag4, diag5) == np.inf - assert approx(wasserstein_distance(diag5, diag6, order=1, internal_p=np.inf), 4.) + assert wasserstein_distance(diag5, diag6, order=1, internal_p=np.inf) == approx(4.) def hera_wrap(delta): def fun(*kargs,**kwargs): -- cgit v1.2.3 From 5c037fb06250e93ad04bb45bdbceb937701e03fa Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 7 Feb 2020 16:32:33 +0100 Subject: Bad link for last version --- src/common/doc/header.html | 2 +- src/python/doc/_templates/layout.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/common/doc/header.html b/src/common/doc/header.html index 9fdb2321..99ab6bb7 100644 --- a/src/common/doc/header.html +++ b/src/common/doc/header.html @@ -56,7 +56,7 @@ $extrastylesheet Download diff --git a/src/python/doc/_templates/layout.html b/src/python/doc/_templates/layout.html index 2f2d9c72..a672a281 100644 --- a/src/python/doc/_templates/layout.html +++ b/src/python/doc/_templates/layout.html @@ -201,7 +201,7 @@ Download -- cgit v1.2.3 From 7be3cfef278917dc0c1905588ae88314273909d4 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 7 Feb 2020 19:38:27 +0100 Subject: More uniform notations between the 2 wassersteins --- src/python/gudhi/wasserstein.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/wasserstein.py b/src/python/gudhi/wasserstein.py index db5ddff2..b1cfd588 100644 --- a/src/python/gudhi/wasserstein.py +++ b/src/python/gudhi/wasserstein.py @@ -27,8 +27,8 @@ def _build_dist_matrix(X, Y, order=2., internal_p=2.): ''' :param X: (n x 2) numpy.array encoding the (points of the) first diagram. :param Y: (m x 2) numpy.array encoding the second diagram. - :param internal_p: Ground metric (i.e. norm l_p). :param order: exponent for the Wasserstein metric. + :param internal_p: Ground metric (i.e. norm L^p). :returns: (n+1) x (m+1) np.array encoding the cost matrix C. For 1 <= i <= n, 1 <= j <= m, C[i,j] encodes the distance between X[i] and Y[j], while C[i, m+1] (resp. C[n+1, j]) encodes the distance (to the p) between X[i] (resp Y[j]) and its orthogonal proj onto the diagonal. note also that C[n+1, m+1] = 0 (it costs nothing to move from the diagonal to the diagonal). @@ -54,8 +54,8 @@ def _build_dist_matrix(X, Y, order=2., internal_p=2.): def _perstot(X, order, internal_p): ''' :param X: (n x 2) numpy.array (points of a given diagram). - :param internal_p: Ground metric on the (upper-half) plane (i.e. norm l_p in R^2); Default value is 2 (Euclidean norm). :param order: exponent for Wasserstein. Default value is 2. + :param internal_p: Ground metric on the (upper-half) plane (i.e. norm L^p in R^2); Default value is 2 (Euclidean norm). :returns: float, the total persistence of the diagram (that is, its distance to the empty diagram). ''' Xdiag = _proj_on_diag(X) @@ -66,8 +66,8 @@ def wasserstein_distance(X, Y, order=2., internal_p=2.): ''' :param X: (n x 2) numpy.array encoding the (finite points of the) first diagram. Must not contain essential points (i.e. with infinite coordinate). :param Y: (m x 2) numpy.array encoding the second diagram. - :param internal_p: Ground metric on the (upper-half) plane (i.e. norm l_p in R^2); Default value is 2 (euclidean norm). :param order: exponent for Wasserstein; Default value is 2. + :param internal_p: Ground metric on the (upper-half) plane (i.e. norm L^p in R^2); Default value is 2 (euclidean norm). :returns: the Wasserstein distance of order q (1 <= q < infinity) between persistence diagrams with respect to the internal_p-norm as ground metric. :rtype: float ''' -- cgit v1.2.3 From 458ee3e95c752f09058d933349851c8a3a730cad Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Fri, 7 Feb 2020 19:41:38 +0100 Subject: Name argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Théo Lacombe --- src/python/test/test_wasserstein_distance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/test/test_wasserstein_distance.py b/src/python/test/test_wasserstein_distance.py index 6a14c50e..4bc7114e 100755 --- a/src/python/test/test_wasserstein_distance.py +++ b/src/python/test/test_wasserstein_distance.py @@ -66,7 +66,7 @@ def hera_wrap(delta): return fun def test_wasserstein_distance_pot(): - _basic_wasserstein(pot, 1e-15, False) + _basic_wasserstein(pot, 1e-15, test_infinity=False) def test_wasserstein_distance_hera(): _basic_wasserstein(hera_wrap(1e-12), 1e-12) -- cgit v1.2.3 From b75123eeda446e7f778d4939da67a78e4c8c6abc Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 8 Feb 2020 17:39:05 +0100 Subject: Euclidean with a capital E --- src/Bottleneck_distance/include/gudhi/Persistence_graph.h | 2 +- src/python/doc/wasserstein_distance_user.rst | 2 +- src/python/gudhi/wasserstein.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h index f791e37c..e1e3522e 100644 --- a/src/Bottleneck_distance/include/gudhi/Persistence_graph.h +++ b/src/Bottleneck_distance/include/gudhi/Persistence_graph.h @@ -25,7 +25,7 @@ namespace Gudhi { namespace persistence_diagram { -/** \internal \brief Structure representing an euclidean bipartite graph containing +/** \internal \brief Structure representing a Euclidean bipartite graph containing * the points from the two persistence diagrams (including the projections). * * \ingroup bottleneck_distance diff --git a/src/python/doc/wasserstein_distance_user.rst b/src/python/doc/wasserstein_distance_user.rst index 99445b99..94b454e2 100644 --- a/src/python/doc/wasserstein_distance_user.rst +++ b/src/python/doc/wasserstein_distance_user.rst @@ -28,7 +28,7 @@ Morozov, and Arnur Nigmetov. Basic example ------------- -This example computes the 1-Wasserstein distance from 2 persistence diagrams with euclidean ground metric. +This example computes the 1-Wasserstein distance from 2 persistence diagrams with Euclidean ground metric. Note that persistence diagrams must be submitted as (n x 2) numpy arrays and must not contain inf values. .. testcode:: diff --git a/src/python/gudhi/wasserstein.py b/src/python/gudhi/wasserstein.py index b1cfd588..13102094 100644 --- a/src/python/gudhi/wasserstein.py +++ b/src/python/gudhi/wasserstein.py @@ -67,7 +67,7 @@ def wasserstein_distance(X, Y, order=2., internal_p=2.): :param X: (n x 2) numpy.array encoding the (finite points of the) first diagram. Must not contain essential points (i.e. with infinite coordinate). :param Y: (m x 2) numpy.array encoding the second diagram. :param order: exponent for Wasserstein; Default value is 2. - :param internal_p: Ground metric on the (upper-half) plane (i.e. norm L^p in R^2); Default value is 2 (euclidean norm). + :param internal_p: Ground metric on the (upper-half) plane (i.e. norm L^p in R^2); Default value is 2 (Euclidean norm). :returns: the Wasserstein distance of order q (1 <= q < infinity) between persistence diagrams with respect to the internal_p-norm as ground metric. :rtype: float ''' -- cgit v1.2.3 From ee0f12f1df406c81c6ad860c494eed908021fad9 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Sat, 8 Feb 2020 19:54:46 +0100 Subject: Use setuptools.find_packages --- src/python/setup.py.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/setup.py.in b/src/python/setup.py.in index f993165c..bd7fb180 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -8,7 +8,7 @@ - YYYY/MM Author: Description of the modification """ -from setuptools import setup, Extension +from setuptools import setup, Extension, find_packages from Cython.Build import cythonize from numpy import get_include as numpy_get_include import sys @@ -44,7 +44,7 @@ for module in modules: setup( name = 'gudhi', - packages=["gudhi","gudhi.representations"], + packages=find_packages(), # find_namespace_packages(include=["gudhi*"]) author='GUDHI Editorial Board', author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', -- cgit v1.2.3 From d6f3165831d20bf3a91f1ff7e9734a574eaa567a Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 11 Feb 2020 13:06:48 +0100 Subject: License and author --- src/python/gudhi/hera.cc | 13 +++++++++++-- src/python/test/test_wasserstein_distance.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/hera.cc b/src/python/gudhi/hera.cc index 61f0da10..0d562b4c 100644 --- a/src/python/gudhi/hera.cc +++ b/src/python/gudhi/hera.cc @@ -1,9 +1,19 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Marc Glisse + * + * Copyright (C) 2020 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + #include #include #include -#include +#include // Hera #include @@ -41,7 +51,6 @@ double wasserstein_distance( PYBIND11_MODULE(hera, m) { m.def("wasserstein_distance", &wasserstein_distance, py::arg("X"), py::arg("Y"), - // Should we name those q, p and d instead? py::arg("order") = 1, py::arg("internal_p") = std::numeric_limits::infinity(), py::arg("delta") = .01, diff --git a/src/python/test/test_wasserstein_distance.py b/src/python/test/test_wasserstein_distance.py index 4bc7114e..6a6b217b 100755 --- a/src/python/test/test_wasserstein_distance.py +++ b/src/python/test/test_wasserstein_distance.py @@ -1,6 +1,6 @@ """ This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - Author(s): Theo Lacombe + Author(s): Theo Lacombe, Marc Glisse Copyright (C) 2019 Inria -- cgit v1.2.3 From ab018a79b1d71b9db17056303785517934cd9157 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 12 Feb 2020 10:08:06 +0100 Subject: Fix code coverage generation --- src/cmake/modules/GUDHI_boost_test.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cmake/modules/GUDHI_boost_test.cmake b/src/cmake/modules/GUDHI_boost_test.cmake index 3b9da78f..4a13404b 100644 --- a/src/cmake/modules/GUDHI_boost_test.cmake +++ b/src/cmake/modules/GUDHI_boost_test.cmake @@ -9,7 +9,6 @@ if (WITH_GUDHI_BOOST_TEST_COVERAGE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") endif() set(GUDHI_UT_LOG_FORMAT "--log_format=XML") - set(GUDHI_UT_LOG_SINK "--log_sink=${CMAKE_BINARY_DIR}/${unitary_test}_UT.xml") set(GUDHI_UT_LOG_LEVEL "--log_level=test_suite") set(GUDHI_UT_REPORT_LEVEL "--report_level=no") else (WITH_GUDHI_BOOST_TEST_COVERAGE) @@ -19,6 +18,10 @@ else (WITH_GUDHI_BOOST_TEST_COVERAGE) endif(WITH_GUDHI_BOOST_TEST_COVERAGE) function(gudhi_add_boost_test unitary_test) + if (WITH_GUDHI_BOOST_TEST_COVERAGE) + set(GUDHI_UT_LOG_SINK "--log_sink=${CMAKE_BINARY_DIR}/${unitary_test}_UT.xml") + endif(WITH_GUDHI_BOOST_TEST_COVERAGE) + target_link_libraries(${unitary_test} Boost::unit_test_framework) add_test(NAME ${unitary_test} COMMAND $ ${GUDHI_UT_LOG_FORMAT} ${GUDHI_UT_LOG_SINK} -- cgit v1.2.3 From 89911f674b79c930a6f936a092748e4070d99e46 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 12 Feb 2020 10:08:45 +0100 Subject: Make boost available even if cmake is < 3.5 --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- .../modules/GUDHI_third_party_libraries.cmake | 35 ++++++++++++++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 298e71ca..d9244dc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.1) project(GUDHIdev) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e799a3a..561aa049 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.1) project(GUDHI) diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index 10b2b56a..6f01dc85 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -6,6 +6,38 @@ if(NOT Boost_FOUND) message(FATAL_ERROR "NOTICE: This program requires Boost and will not be compiled.") endif(NOT Boost_FOUND) +# cf. https://cliutils.gitlab.io/modern-cmake/chapters/packages/Boost.html +# This is needed if your Boost version is newer than your CMake version +# or if you have an old version of CMake (<3.5) +if(NOT TARGET Boost::program_options) + add_library(Boost::program_options IMPORTED INTERFACE) + set_property(TARGET Boost::program_options PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) + set_property(TARGET Boost::program_options PROPERTY + INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) +endif() +if(NOT TARGET Boost::filesystem) + add_library(Boost::filesystem IMPORTED INTERFACE) + set_property(TARGET Boost::filesystem PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) + set_property(TARGET Boost::filesystem PROPERTY + INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) +endif() +if(NOT TARGET Boost::unit_test_framework) + add_library(Boost::unit_test_framework IMPORTED INTERFACE) + set_property(TARGET Boost::unit_test_framework PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) + set_property(TARGET Boost::unit_test_framework PROPERTY + INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) +endif() +if(NOT TARGET Boost::system) + add_library(Boost::system IMPORTED INTERFACE) + set_property(TARGET Boost::system PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) + set_property(TARGET Boost::system PROPERTY + INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) +endif() + find_package(GMP) if(GMP_FOUND) INCLUDE_DIRECTORIES(${GMP_INCLUDE_DIR}) @@ -82,9 +114,6 @@ add_definitions( -DBOOST_ALL_DYN_LINK ) # problem on Mac with boost_system and boost_thread add_definitions( -DBOOST_SYSTEM_NO_DEPRECATED ) -#INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) -#LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) - message(STATUS "boost include dirs:" ${Boost_INCLUDE_DIRS}) message(STATUS "boost library dirs:" ${Boost_LIBRARY_DIRS}) -- cgit v1.2.3 From b2c1cf839080efa43835d7b0fdcd6a38f6808255 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 26 Feb 2020 10:20:00 +0100 Subject: Fix #229 incomplete citation in nerve_GIC python documentation --- src/python/gudhi/nerve_gic.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/nerve_gic.pyx b/src/python/gudhi/nerve_gic.pyx index 382e71c5..45cc8eba 100644 --- a/src/python/gudhi/nerve_gic.pyx +++ b/src/python/gudhi/nerve_gic.pyx @@ -187,7 +187,7 @@ cdef class CoverComplex: 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 + length avoiding discretization artifacts - see :cite:`Carriere17c`) for a functional cover. :rtype: double @@ -288,7 +288,7 @@ cdef class CoverComplex: 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. + automatically tuned with subsampling - see :cite:`Carriere17c`. :param N: Number of subsampling iteration (the default reasonable value is 100, but there is no guarantee on how to choose it). -- cgit v1.2.3