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/cmake/modules') 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/cmake/modules') 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 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/cmake/modules') 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 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/cmake/modules') 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