diff options
-rw-r--r-- | .github/workflows/pip-packaging-linux.yml | 56 | ||||
-rw-r--r-- | .github/workflows/pip-packaging-osx.yml | 44 | ||||
-rw-r--r-- | .github/workflows/pip-packaging-windows.yml | 42 | ||||
-rw-r--r-- | Dockerfile_for_circleci_image | 2 | ||||
-rw-r--r-- | Dockerfile_for_pip | 49 | ||||
-rw-r--r-- | Dockerfile_gudhi_installation | 2 | ||||
m--------- | ext/hera | 0 | ||||
-rw-r--r-- | src/cmake/modules/GUDHI_third_party_libraries.cmake | 5 | ||||
-rw-r--r-- | src/cmake/modules/GUDHI_user_version_target.cmake | 7 | ||||
-rw-r--r-- | src/python/CMakeLists.txt | 11 | ||||
-rw-r--r-- | src/python/doc/bottleneck_distance_user.rst | 19 | ||||
-rw-r--r-- | src/python/doc/installation.rst | 37 | ||||
-rw-r--r-- | src/python/gudhi/bottleneck.cc | 3 | ||||
-rw-r--r-- | src/python/gudhi/hera/__init__.py | 7 | ||||
-rw-r--r-- | src/python/gudhi/hera/bottleneck.cc | 54 | ||||
-rw-r--r-- | src/python/gudhi/hera/wasserstein.cc (renamed from src/python/gudhi/hera.cc) | 2 | ||||
-rw-r--r-- | src/python/include/pybind11_diagram_utils.h | 8 | ||||
-rw-r--r-- | src/python/introduction.rst | 24 | ||||
-rw-r--r-- | src/python/setup.py.in | 27 | ||||
-rwxr-xr-x | src/python/test/test_bottleneck_distance.py | 6 |
20 files changed, 376 insertions, 29 deletions
diff --git a/.github/workflows/pip-packaging-linux.yml b/.github/workflows/pip-packaging-linux.yml new file mode 100644 index 00000000..bd524af9 --- /dev/null +++ b/.github/workflows/pip-packaging-linux.yml @@ -0,0 +1,56 @@ +name: pip packaging linux + +on: + release: + types: [published] + +jobs: + build: + name: build pip wheels + runs-on: ubuntu-latest + container: gudhi/pip_for_gudhi + steps: + - uses: actions/checkout@v1 + with: + submodules: true + - name: Build wheels for Python 3.5 + run: | + mkdir build_35 + cd build_35 + cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=$PYTHON35/bin/python .. + cd src/python + $PYTHON35/bin/python setup.py bdist_wheel + auditwheel repair dist/*.whl + - name: Build wheels for Python 3.6 + run: | + mkdir build_36 + cd build_36 + cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=$PYTHON36/bin/python .. + cd src/python + $PYTHON36/bin/python setup.py bdist_wheel + auditwheel repair dist/*.whl + - name: Build wheels for Python 3.7 + run: | + mkdir build_37 + cd build_37 + cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=$PYTHON37/bin/python .. + cd src/python + $PYTHON37/bin/python setup.py bdist_wheel + auditwheel repair dist/*.whl + - name: Build wheels for Python 3.8 + run: | + mkdir build_38 + cd build_38 + cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=$PYTHON38/bin/python .. + cd src/python + $PYTHON38/bin/python setup.py bdist_wheel + auditwheel repair dist/*.whl + - name: Publish on PyPi + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + $PYTHON38/bin/python -m twine upload build_35/src/python/wheelhouse/* + $PYTHON38/bin/python -m twine upload build_36/src/python/wheelhouse/* + $PYTHON38/bin/python -m twine upload build_37/src/python/wheelhouse/* + $PYTHON38/bin/python -m twine upload build_38/src/python/wheelhouse/*
\ No newline at end of file diff --git a/.github/workflows/pip-packaging-osx.yml b/.github/workflows/pip-packaging-osx.yml new file mode 100644 index 00000000..85c3c807 --- /dev/null +++ b/.github/workflows/pip-packaging-osx.yml @@ -0,0 +1,44 @@ +name: pip packaging osx + +on: + release: + types: [published] + +jobs: + build: + runs-on: macos-latest + strategy: + max-parallel: 4 + matrix: + python-version: ['3.5', '3.6', '3.7', '3.8'] + name: Build wheels for Python ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v1 + with: + submodules: true + - uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + - name: Install dependencies + run: | + brew update && brew install boost eigen gmp mpfr cgal + python -m pip install --user -r .github/build-requirements.txt + python -m pip install --user twine delocate + - name: Build python wheel + run: | + python --version + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DPython_ADDITIONAL_VERSIONS=3 .. + cd src/python + python setup.py bdist_wheel + - name: Publish on PyPi + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + mkdir wheelhouse + /Users/runner/.local/bin/delocate-listdeps build/src/python/dist/* + /Users/runner/.local/bin/delocate-wheel --require-archs x86_64 -w wheelhouse build/src/python/dist/* + python -m twine upload wheelhouse/*
\ No newline at end of file diff --git a/.github/workflows/pip-packaging-windows.yml b/.github/workflows/pip-packaging-windows.yml new file mode 100644 index 00000000..1cadf6b1 --- /dev/null +++ b/.github/workflows/pip-packaging-windows.yml @@ -0,0 +1,42 @@ +name: pip packaging windows + +on: + release: + types: [published] + +jobs: + build: + runs-on: windows-latest + strategy: + max-parallel: 4 + matrix: + python-version: ['3.5', '3.6', '3.7', '3.8'] + name: Build wheels for Python ${{ matrix.python-version }} + steps: + - uses: actions/checkout@v1 + with: + submodules: true + - uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + - name: Install dependencies + run: | + vcpkg install boost-graph:x64-windows boost-serialization:x64-windows boost-date-time:x64-windows boost-system:x64-windows boost-filesystem:x64-windows boost-units:x64-windows boost-thread:x64-windows boost-program-options:x64-windows eigen3:x64-windows mpfr:x64-windows mpir:x64-windows cgal:x64-windows + python -m pip install --user -r .github/build-requirements.txt + python -m pip install --user twine + - name: Build python wheel + run: | + python --version + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DGMP_INCLUDE_DIR="c:/vcpkg/installed/x64-windows/include" -DGMP_LIBRARIES="c:/vcpkg/installed/x64-windows/lib/mpir.lib" -DGMP_LIBRARIES_DIR="c:/vcpkg/installed/x64-windows/lib" -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DPython_ADDITIONAL_VERSIONS=3 .. + cd src/python + cp c:/vcpkg/installed/x64-windows/bin/mpfr.dll gudhi/ + cp c:/vcpkg/installed/x64-windows/bin/mpir.dll gudhi/ + python setup.py bdist_wheel + - name: Publish on PyPi + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: python -m twine upload build/src/python/dist/* diff --git a/Dockerfile_for_circleci_image b/Dockerfile_for_circleci_image index c2e8a8f5..464097e7 100644 --- a/Dockerfile_for_circleci_image +++ b/Dockerfile_for_circleci_image @@ -1,4 +1,4 @@ -FROM ubuntu:19.04 +FROM ubuntu:20.04 # Update and upgrade distribution RUN apt-get update && \ diff --git a/Dockerfile_for_pip b/Dockerfile_for_pip new file mode 100644 index 00000000..8f60e37c --- /dev/null +++ b/Dockerfile_for_pip @@ -0,0 +1,49 @@ +FROM quay.io/pypa/manylinux2014_x86_64 + +RUN yum -y update && yum -y install \ + wget \ + zlib-devel \ + eigen3-devel \ + mpfr-devel \ + gmp-devel \ + devtoolset-8 \ + && yum clean all + +RUN mkdir -p /opt/cmake \ + && wget https://github.com/Kitware/CMake/releases/download/v3.16.2/cmake-3.16.2-Linux-x86_64.sh \ + && sh cmake-3.16.2-Linux-x86_64.sh --skip-license --prefix=/opt/cmake \ + && rm -f cmake-3.16.2-Linux-x86_64.sh + +RUN git clone -b boost-1.73.0 --depth 1 https://github.com/boostorg/boost.git \ + && cd boost \ + && git submodule update --init \ + && ./bootstrap.sh --with-libraries=filesystem,program_options,system,thread,test \ + && ./b2 headers \ + && ./b2 install \ + && cd .. \ + && rm -rf boost + +RUN wget https://github.com/CGAL/cgal/releases/download/releases%2FCGAL-5.0.2/CGAL-5.0.2.tar.xz \ + && tar xf CGAL-5.0.2.tar.xz \ + && mkdir build \ + && cd build \ + && /opt/cmake/bin/cmake -DCMAKE_BUILD_TYPE=Release ../CGAL-5.0.2/ \ + && make install \ + && cd .. \ + && rm -rf build CGAL-5.0.2 + +ADD .github/build-requirements.txt / + +RUN /opt/python/cp35-cp35m/bin/pip install -r build-requirements.txt \ + && /opt/python/cp36-cp36m/bin/pip install -r build-requirements.txt\ + && /opt/python/cp37-cp37m/bin/pip install -r build-requirements.txt\ + && /opt/python/cp38-cp38/bin/pip install -r build-requirements.txt\ + && /opt/python/cp38-cp38/bin/pip install twine + +ENV PYTHON35="/opt/python/cp35-cp35m/" +ENV PYTHON36="/opt/python/cp36-cp36m/" +ENV PYTHON37="/opt/python/cp37-cp37m/" +ENV PYTHON38="/opt/python/cp38-cp38/" + +ENV PATH="/opt/cmake/bin:${PATH}" +ENV PATH="/opt/rh/devtoolset-8/root/usr/bin:${PATH}" diff --git a/Dockerfile_gudhi_installation b/Dockerfile_gudhi_installation index 461a8a19..996dd06b 100644 --- a/Dockerfile_gudhi_installation +++ b/Dockerfile_gudhi_installation @@ -1,4 +1,4 @@ -FROM ubuntu:19.04 +FROM ubuntu:20.04 # Update and upgrade distribution RUN apt-get update && \ diff --git a/ext/hera b/ext/hera -Subproject 0019cae9dc1e9d11aa03bc59681435ba7f21eea +Subproject b73ed1face2c609958556e6f2b7704bbd8aaa26 diff --git a/src/cmake/modules/GUDHI_third_party_libraries.cmake b/src/cmake/modules/GUDHI_third_party_libraries.cmake index f92fe93e..a56a2756 100644 --- a/src/cmake/modules/GUDHI_third_party_libraries.cmake +++ b/src/cmake/modules/GUDHI_third_party_libraries.cmake @@ -68,7 +68,10 @@ if(CGAL_FOUND) 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/wasserstein/include CACHE PATH "Directory where one can find Hera's wasserstein.h") +set(HERA_WASSERSTEIN_INTERNAL_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/ext/hera/wasserstein/include) +set(HERA_WASSERSTEIN_INCLUDE_DIR ${HERA_WASSERSTEIN_INTERNAL_INCLUDE_DIR} CACHE PATH "Directory where one can find Hera's wasserstein.h") +set(HERA_BOTTLENECK_INTERNAL_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/ext/hera/bottleneck/include) +set(HERA_BOTTLENECK_INCLUDE_DIR ${HERA_BOTTLENECK_INTERNAL_INCLUDE_DIR} CACHE PATH "Directory where one can find Hera's bottleneck.h") option(WITH_GUDHI_USE_TBB "Build with Intel TBB parallelization" ON) diff --git a/src/cmake/modules/GUDHI_user_version_target.cmake b/src/cmake/modules/GUDHI_user_version_target.cmake index e99bb42d..e4f39aae 100644 --- a/src/cmake/modules/GUDHI_user_version_target.cmake +++ b/src/cmake/modules/GUDHI_user_version_target.cmake @@ -67,8 +67,11 @@ 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/wasserstein/include ${GUDHI_USER_VERSION_DIR}/ext/hera/wasserstein/include) +if(HERA_WASSERSTEIN_INCLUDE_DIR STREQUAL HERA_WASSERSTEIN_INTERNAL_INCLUDE_DIR OR + HERA_BOTTLENECK_INCLUDE_DIR STREQUAL HERA_BOTTLENECK_INTERNAL_INCLUDE_DIR) + add_custom_command(TARGET user_version PRE_BUILD COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_SOURCE_DIR}/ext/hera ${GUDHI_USER_VERSION_DIR}/ext/hera) +endif() set(GUDHI_DIRECTORIES "doc;example;concept;utilities") diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 96dd3f6f..81be1b76 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -130,7 +130,8 @@ if(PYTHONINTERP_FOUND) 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', ") - set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'hera', ") + set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'hera/wasserstein', ") + set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'hera/bottleneck', ") if (NOT CGAL_VERSION VERSION_LESS 4.11.0) set(GUDHI_PYBIND11_MODULES "${GUDHI_PYBIND11_MODULES}'bottleneck', ") set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'nerve_gic', ") @@ -236,6 +237,10 @@ if(PYTHONINTERP_FOUND) file(COPY "gudhi/point_cloud" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") file(COPY "gudhi/weighted_rips_complex.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") file(COPY "gudhi/dtm_rips_complex.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") + file(COPY "gudhi/hera/__init__.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi/hera") + + # Some files for pip package + file(COPY "introduction.rst" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/") add_custom_command( OUTPUT gudhi.so @@ -355,7 +360,9 @@ if(PYTHONINTERP_FOUND) 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) + if (PYBIND11_FOUND) + add_gudhi_py_test(test_bottleneck_distance) + endif() # Cover complex file(COPY ${CMAKE_SOURCE_DIR}/data/points/human.off DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) diff --git a/src/python/doc/bottleneck_distance_user.rst b/src/python/doc/bottleneck_distance_user.rst index 89da89d3..6c6e08d9 100644 --- a/src/python/doc/bottleneck_distance_user.rst +++ b/src/python/doc/bottleneck_distance_user.rst @@ -9,14 +9,23 @@ Definition .. include:: bottleneck_distance_sum.inc -This implementation is based on ideas from "Geometry Helps in Bottleneck Matching and Related Problems" -:cite:`DBLP:journals/algorithmica/EfratIK01`. Another relevant publication, although it was not used is -"Geometry Helps to Compare Persistence Diagrams" :cite:`Kerber:2017:GHC:3047249.3064175`. +This implementation by François Godi is based on ideas from "Geometry Helps in Bottleneck Matching and Related Problems" +:cite:`DBLP:journals/algorithmica/EfratIK01` and requires `CGAL <installation.html#cgal>`_ (`GPL v3 </licensing/>`_). -Function --------- .. autofunction:: gudhi.bottleneck_distance +This other implementation comes from `Hera +<https://bitbucket.org/grey_narn/hera/src/master/>`_ (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. + +.. warning:: + Beware that its approximation allows for a multiplicative error, while the function above uses an additive error. + +.. autofunction:: gudhi.hera.bottleneck_distance + + Distance computation -------------------- diff --git a/src/python/doc/installation.rst b/src/python/doc/installation.rst index a66e910e..525ca84e 100644 --- a/src/python/doc/installation.rst +++ b/src/python/doc/installation.rst @@ -5,20 +5,47 @@ Installation ############ -Conda -***** -The easiest way to install the Python version of GUDHI is using -`conda <https://gudhi.inria.fr/conda/>`_. +Packages +******** +The easiest way to install the Python version of GUDHI is using pre-built packages. +We recommend `conda <https://gudhi.inria.fr/conda/>`_ + +.. code-block:: bash + + conda install -c conda-forge gudhi + +Gudhi is also available on `PyPI <https://pypi.org/project/gudhi/>`_ + +.. code-block:: bash + + pip install gudhi + +Third party packages are also available, for instance on Debian or Ubuntu + +.. code-block:: bash + + apt install python3-gudhi + +In all cases, you may still want to install some of the optional `run time dependencies`_. Compiling ********* +These instructions are for people who want to compile gudhi from source, they are +unnecessary if you installed a binary package of Gudhi as above. They assume that +you have downloaded a `release <https://github.com/GUDHI/gudhi-devel/releases>`_, +with a name like `gudhi.3.2.0.tar.gz`, then run `tar xf gudhi.3.2.0.tar.gz`, which +created a directory `gudhi.3.2.0`, hereinafter referred to as `/path-to-gudhi/`. +If you are instead using a git checkout, beware that the paths are a bit +different, and in particular the `python/` subdirectory is actually `src/python/` +there. + The library uses c++14 and requires `Boost <https://www.boost.org/>`_ :math:`\geq` 1.56.0, `CMake <https://www.cmake.org/>`_ :math:`\geq` 3.1 to generate makefiles, `NumPy <http://numpy.org>`_, `Cython <https://www.cython.org/>`_ and `pybind11 <https://github.com/pybind/pybind11>`_ to compile the GUDHI Python module. It is a multi-platform library and compiles on Linux, Mac OSX and Visual -Studio 2017. +Studio 2017 or later. On `Windows <https://wiki.python.org/moin/WindowsCompilers>`_ , only Python :math:`\geq` 3.5 are available because of the required Visual Studio version. diff --git a/src/python/gudhi/bottleneck.cc b/src/python/gudhi/bottleneck.cc index 838bf9eb..8a3d669a 100644 --- a/src/python/gudhi/bottleneck.cc +++ b/src/python/gudhi/bottleneck.cc @@ -33,7 +33,8 @@ PYBIND11_MODULE(bottleneck, m) { py::arg("diagram_1"), py::arg("diagram_2"), py::arg("e") = py::none(), R"pbdoc( - This function returns the point corresponding to a given vertex. + Compute the Bottleneck distance between two diagrams. + Points at infinity and on the diagonal are supported. :param diagram_1: The first diagram. :type diagram_1: numpy array of shape (m,2) diff --git a/src/python/gudhi/hera/__init__.py b/src/python/gudhi/hera/__init__.py new file mode 100644 index 00000000..f70b92b9 --- /dev/null +++ b/src/python/gudhi/hera/__init__.py @@ -0,0 +1,7 @@ +from .wasserstein import wasserstein_distance +from .bottleneck import bottleneck_distance + + +__author__ = "Marc Glisse" +__copyright__ = "Copyright (C) 2020 Inria" +__license__ = "MIT" diff --git a/src/python/gudhi/hera/bottleneck.cc b/src/python/gudhi/hera/bottleneck.cc new file mode 100644 index 00000000..0cb562ce --- /dev/null +++ b/src/python/gudhi/hera/bottleneck.cc @@ -0,0 +1,54 @@ +/* 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 <pybind11_diagram_utils.h> + +#ifdef _MSC_VER +// https://github.com/grey-narn/hera/issues/3 +// ssize_t is a non-standard type (well, posix) +using py::ssize_t; +#endif + +#include <bottleneck.h> // Hera + +double bottleneck_distance(Dgm d1, Dgm d2, double delta) +{ + // I *think* the call to request() has to be before releasing the GIL. + auto diag1 = numpy_to_range_of_pairs(d1); + auto diag2 = numpy_to_range_of_pairs(d2); + + py::gil_scoped_release release; + + if (delta == 0) + return hera::bottleneckDistExact(diag1, diag2); + else + return hera::bottleneckDistApprox(diag1, diag2, delta); +} + +PYBIND11_MODULE(bottleneck, m) { + m.def("bottleneck_distance", &bottleneck_distance, + py::arg("X"), py::arg("Y"), + py::arg("delta") = .01, + R"pbdoc( + Compute the Bottleneck distance between two diagrams. + Points at infinity are supported. + + .. note:: + Points on the diagonal are not supported and must be filtered out before calling this function. + + Parameters: + X (n x 2 numpy array): First diagram + Y (n x 2 numpy array): Second diagram + delta (float): Relative error 1+delta + + Returns: + float: (approximate) bottleneck distance d_B(X,Y) + )pbdoc"); +} diff --git a/src/python/gudhi/hera.cc b/src/python/gudhi/hera/wasserstein.cc index ea80a9a8..1a21f02f 100644 --- a/src/python/gudhi/hera.cc +++ b/src/python/gudhi/hera/wasserstein.cc @@ -33,7 +33,7 @@ double wasserstein_distance( return hera::wasserstein_dist(diag1, diag2, params); } -PYBIND11_MODULE(hera, m) { +PYBIND11_MODULE(wasserstein, m) { m.def("wasserstein_distance", &wasserstein_distance, py::arg("X"), py::arg("Y"), py::arg("order") = 1, diff --git a/src/python/include/pybind11_diagram_utils.h b/src/python/include/pybind11_diagram_utils.h index d9627258..2d5194f4 100644 --- a/src/python/include/pybind11_diagram_utils.h +++ b/src/python/include/pybind11_diagram_utils.h @@ -18,8 +18,8 @@ namespace py = pybind11; typedef py::array_t<double> Dgm; // Get m[i,0] and m[i,1] as a pair -static auto pairify(void* p, ssize_t h, ssize_t w) { - return [=](ssize_t i){ +static auto pairify(void* p, py::ssize_t h, py::ssize_t w) { + return [=](py::ssize_t i){ char* birth = (char*)p + i * h; char* death = birth + w; return std::make_pair(*(double*)birth, *(double*)death); @@ -32,8 +32,8 @@ inline auto numpy_to_range_of_pairs(py::array_t<double> dgm) { if((buf.ndim!=2 || buf.shape[1]!=2) && (buf.ndim!=1 || buf.shape[0]!=0)) throw std::runtime_error("Diagram must be an array of size n x 2"); // In the case of shape (0), avoid reading non-existing strides[1] even if we won't use it. - ssize_t stride1 = buf.ndim == 2 ? buf.strides[1] : 0; - auto cnt = boost::counting_range<ssize_t>(0, buf.shape[0]); + py::ssize_t stride1 = buf.ndim == 2 ? buf.strides[1] : 0; + auto cnt = boost::counting_range<py::ssize_t>(0, buf.shape[0]); return boost::adaptors::transform(cnt, pairify(buf.ptr, buf.strides[0], stride1)); // Be careful that the returned range cannot contain references to dead temporaries. } diff --git a/src/python/introduction.rst b/src/python/introduction.rst new file mode 100644 index 00000000..11c06ac5 --- /dev/null +++ b/src/python/introduction.rst @@ -0,0 +1,24 @@ +The Gudhi library is an open source library for Computational Topology and +Topological Data Analysis (TDA). It offers state-of-the-art algorithms +to construct various types of simplicial complexes, data structures to +represent them, and algorithms to compute geometric approximations of shapes +and persistent homology. + +The GUDHI library offers the following interoperable modules: + +* Complexes: + * Cubical + * Simplicial: Rips, Witness, Alpha and Čech complexes + * Cover: Nerve and Graph induced complexes +* Data structures and basic operations: + * Simplex tree, Skeleton blockers and Toplex map + * Construction, update, filtration and simplification +* Topological descriptors computation +* Manifold reconstruction +* Topological descriptors tools: + * Bottleneck distance + * Statistical tools + * Persistence diagram and barcode + +For more information about Topological Data Analysis and its workflow, please +refer to the `Wikipedia TDA dedicated page <https://en.wikipedia.org/wiki/Topological_data_analysis>`_. diff --git a/src/python/setup.py.in b/src/python/setup.py.in index b9f4e3f0..98d058fc 100644 --- a/src/python/setup.py.in +++ b/src/python/setup.py.in @@ -48,10 +48,12 @@ ext_modules = cythonize(ext_modules) for module in pybind11_modules: my_include_dirs = include_dirs + [pybind11.get_include(False), pybind11.get_include(True)] - if module == 'hera': + if module == 'hera/wasserstein': my_include_dirs = ['@HERA_WASSERSTEIN_INCLUDE_DIR@'] + my_include_dirs + elif module == 'hera/bottleneck': + my_include_dirs = ['@HERA_BOTTLENECK_INCLUDE_DIR@'] + my_include_dirs ext_modules.append(Extension( - 'gudhi.' + module, + 'gudhi.' + module.replace('/', '.'), sources = [source_dir + module + '.cc'], language = 'c++', include_dirs = my_include_dirs, @@ -62,14 +64,29 @@ for module in pybind11_modules: runtime_library_dirs=runtime_library_dirs, )) +# read the contents of introduction.rst +with open("introduction.rst", "r") as fh: + long_description = fh.read() + setup( name = 'gudhi', packages=find_packages(), # find_namespace_packages(include=["gudhi*"]) author='GUDHI Editorial Board', author_email='gudhi-contact@lists.gforge.inria.fr', version='@GUDHI_VERSION@', - url='http://gudhi.gforge.inria.fr/', + url='https://gudhi.inria.fr/', + project_urls={ + 'Bug Tracker': 'https://github.com/GUDHI/gudhi-devel/issues', + 'Documentation': 'https://gudhi.inria.fr/python/latest/', + 'Source Code': 'https://github.com/GUDHI/gudhi-devel', + 'License': 'https://gudhi.inria.fr/licensing/' + }, + description='The Gudhi library is an open source library for ' \ + 'Computational Topology and Topological Data Analysis (TDA).', + long_description_content_type='text/x-rst', + long_description=long_description, ext_modules = ext_modules, - install_requires = ['cython','numpy >= 1.9',], - setup_requires = ['numpy >= 1.9','pybind11',], + install_requires = ['numpy >= 1.9',], + setup_requires = ['cython','numpy >= 1.9','pybind11',], + package_data={"": ["*.dll"], }, ) diff --git a/src/python/test/test_bottleneck_distance.py b/src/python/test/test_bottleneck_distance.py index 70b2abad..6915bea8 100755 --- a/src/python/test/test_bottleneck_distance.py +++ b/src/python/test/test_bottleneck_distance.py @@ -9,6 +9,8 @@ """ import gudhi +import gudhi.hera +import pytest __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2016 Inria" @@ -19,5 +21,7 @@ def test_basic_bottleneck(): diag1 = [[2.7, 3.7], [9.6, 14.0], [34.2, 34.974], [3.0, float("Inf")]] diag2 = [[2.8, 4.45], [9.5, 14.1], [3.2, float("Inf")]] - assert gudhi.bottleneck_distance(diag1, diag2, 0.1) == 0.8081763781405569 assert gudhi.bottleneck_distance(diag1, diag2) == 0.75 + assert gudhi.bottleneck_distance(diag1, diag2, 0.1) == pytest.approx(0.75, abs=0.1) + assert gudhi.hera.bottleneck_distance(diag1, diag2, 0) == 0.75 + assert gudhi.hera.bottleneck_distance(diag1, diag2, 0.1) == pytest.approx(0.75, rel=0.1) |