diff options
-rw-r--r-- | .circleci/config.yml | 126 | ||||
-rw-r--r-- | src/python/CMakeLists.txt | 6 | ||||
-rwxr-xr-x | src/python/example/diagram_vectorizations_distances_kernels.py | 19 | ||||
-rw-r--r-- | src/python/gudhi/__init__.py.in | 4 | ||||
-rw-r--r-- | src/python/gudhi/simplex_tree.pxd | 2 | ||||
-rw-r--r-- | src/python/gudhi/simplex_tree.pyx | 3 | ||||
-rw-r--r-- | src/python/include/Simplex_tree_interface.h | 6 | ||||
-rwxr-xr-x | src/python/test/test_simplex_tree.py | 17 |
8 files changed, 169 insertions, 14 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 285a66a5..d95b8d36 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -95,10 +95,136 @@ jobs: path: /tmp/doxygen destination: doxygen + examples_without_cgal_eigen: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test examples without cgal and eigen + command: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF .. + make all + ctest --output-on-failure + + tests_without_cgal_eigen: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test unitary tests without cgal and eigen + command: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF .. + make all + ctest --output-on-failure + + utils_without_cgal_eigen: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test utilities without cgal and eigen + command: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF .. + make all + ctest --output-on-failure + + python_without_cgal_eigen: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test python module without cgal and eigen + command: | + git submodule init + git submodule update + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=ON -DPython_ADDITIONAL_VERSIONS=3 .. + cd src/python + python3 setup.py build_ext --inplace + ctest --output-on-failure + + examples_without_cgal: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test examples without cgal + command: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DEIGEN3_INCLUDE_DIR=/eigen-3.3.9 -DWITH_GUDHI_EXAMPLE=ON -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF .. + make all + ctest --output-on-failure + + tests_without_cgal: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test unitary tests without cgal + command: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DEIGEN3_INCLUDE_DIR=/eigen-3.3.9 -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=ON -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=OFF .. + make all + ctest --output-on-failure + + utils_without_cgal: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test utilities without cgal + command: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DEIGEN3_INCLUDE_DIR=/eigen-3.3.9 -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_TEST=OFF -DWITH_GUDHI_UTILITIES=ON -DWITH_GUDHI_PYTHON=OFF .. + make all + ctest --output-on-failure + + python_without_cgal: + docker: + - image: gudhi/ci_for_gudhi_wo_cgal:latest + steps: + - checkout + - run: + name: Build and test python module without cgal + command: | + git submodule init + git submodule update + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release -DEIGEN3_INCLUDE_DIR=/eigen-3.3.9 -DWITH_GUDHI_EXAMPLE=OFF -DWITH_GUDHI_UTILITIES=OFF -DWITH_GUDHI_PYTHON=ON -DPython_ADDITIONAL_VERSIONS=3 .. + cd src/python + python3 setup.py build_ext --inplace + ctest --output-on-failure + workflows: version: 2 build: jobs: + - examples_without_cgal_eigen + - tests_without_cgal_eigen + - utils_without_cgal_eigen + - python_without_cgal_eigen + - examples_without_cgal + - tests_without_cgal + - utils_without_cgal + - python_without_cgal - examples - tests - utils diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 56b6876c..5c1402a6 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -133,6 +133,10 @@ if(PYTHONINTERP_FOUND) add_gudhi_debug_info("Eigen3 version ${EIGEN3_VERSION}") # No problem, even if no CGAL found set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DCGAL_EIGEN3_ENABLED', ") + set(GUDHI_PYTHON_EXTRA_COMPILE_ARGS "${GUDHI_PYTHON_EXTRA_COMPILE_ARGS}'-DGUDHI_USE_EIGEN3', ") + set(GUDHI_USE_EIGEN3 "True") + else (EIGEN3_FOUND) + set(GUDHI_USE_EIGEN3 "False") endif (EIGEN3_FOUND) set(GUDHI_CYTHON_MODULES "${GUDHI_CYTHON_MODULES}'off_reader', ") @@ -504,7 +508,7 @@ if(PYTHONINTERP_FOUND) endif() # Representations - if(SKLEARN_FOUND AND MATPLOTLIB_FOUND) + if(SKLEARN_FOUND AND MATPLOTLIB_FOUND AND OT_FOUND AND NOT CGAL_VERSION VERSION_LESS 4.11.0) add_gudhi_py_test(test_representations) endif() diff --git a/src/python/example/diagram_vectorizations_distances_kernels.py b/src/python/example/diagram_vectorizations_distances_kernels.py index c4a71a7a..2801576e 100755 --- a/src/python/example/diagram_vectorizations_distances_kernels.py +++ b/src/python/example/diagram_vectorizations_distances_kernels.py @@ -5,11 +5,11 @@ import numpy as np from sklearn.kernel_approximation import RBFSampler from sklearn.preprocessing import MinMaxScaler -from gudhi.representations import DiagramSelector, Clamping, Landscape, Silhouette, BettiCurve, ComplexPolynomial,\ +from gudhi.representations import (DiagramSelector, Clamping, Landscape, Silhouette, BettiCurve, ComplexPolynomial,\ TopologicalVector, DiagramScaler, BirthPersistenceTransform,\ PersistenceImage, PersistenceWeightedGaussianKernel, Entropy, \ PersistenceScaleSpaceKernel, SlicedWassersteinDistance,\ - SlicedWassersteinKernel, BottleneckDistance, PersistenceFisherKernel, WassersteinDistance + SlicedWassersteinKernel, PersistenceFisherKernel, WassersteinDistance) D1 = np.array([[0.,4.],[1.,2.],[3.,8.],[6.,8.], [0., np.inf], [5., np.inf]]) @@ -93,14 +93,21 @@ print("SW distance is " + str(sW(D1, D2))) SW = SlicedWassersteinKernel(num_directions=100, bandwidth=1.) print("SW kernel is " + str(SW(D1, D2))) -W = WassersteinDistance(order=2, internal_p=2, mode="pot") -print("Wasserstein distance (POT) is " + str(W(D1, D2))) +try: + W = WassersteinDistance(order=2, internal_p=2, mode="pot") + print("Wasserstein distance (POT) is " + str(W(D1, D2))) +except ImportError: + print("WassersteinDistance (POT) is not available, you may be missing pot.") W = WassersteinDistance(order=2, internal_p=2, mode="hera", delta=0.0001) print("Wasserstein distance (hera) is " + str(W(D1, D2))) -W = BottleneckDistance(epsilon=.001) -print("Bottleneck distance is " + str(W(D1, D2))) +try: + from gudhi.representations import BottleneckDistance + W = BottleneckDistance(epsilon=.001) + print("Bottleneck distance is " + str(W(D1, D2))) +except ImportError: + print("BottleneckDistance is not available, you may be missing CGAL.") PF = PersistenceFisherKernel(bandwidth_fisher=1., bandwidth=1.) print("PF kernel is " + str(PF(D1, D2))) diff --git a/src/python/gudhi/__init__.py.in b/src/python/gudhi/__init__.py.in index 79e12fbc..3043201a 100644 --- a/src/python/gudhi/__init__.py.in +++ b/src/python/gudhi/__init__.py.in @@ -23,6 +23,10 @@ __all__ = [@GUDHI_PYTHON_MODULES@ @GUDHI_PYTHON_MODULES_EXTRA@] __available_modules = '' __missing_modules = '' +# For unitary tests purpose +# could use "if 'collapse_edges' in gudhi.__all__" when collapse edges will have a python module +__GUDHI_USE_EIGEN3 = @GUDHI_USE_EIGEN3@ + # Try to import * from gudhi.__module_name for default modules. # Extra modules require an explicit import by the user (mostly because of # unusual dependencies, but also to avoid cluttering namespace gudhi and diff --git a/src/python/gudhi/simplex_tree.pxd b/src/python/gudhi/simplex_tree.pxd index 3c4cbed3..000323af 100644 --- a/src/python/gudhi/simplex_tree.pxd +++ b/src/python/gudhi/simplex_tree.pxd @@ -63,7 +63,7 @@ cdef extern from "Simplex_tree_interface.h" namespace "Gudhi": bool make_filtration_non_decreasing() nogil void compute_extended_filtration() nogil vector[vector[pair[int, pair[double, double]]]] compute_extended_persistence_subdiagrams(vector[pair[int, pair[double, double]]] dgm, double min_persistence) nogil - Simplex_tree_interface_full_featured* collapse_edges(int nb_collapse_iteration) nogil + Simplex_tree_interface_full_featured* collapse_edges(int nb_collapse_iteration) nogil except + void reset_filtration(double filtration, int dimension) nogil # Iterators over Simplex tree pair[vector[int], double] get_simplex_and_filtration(Simplex_tree_simplex_handle f_simplex) nogil diff --git a/src/python/gudhi/simplex_tree.pyx b/src/python/gudhi/simplex_tree.pyx index cdd2e87b..665d41e6 100644 --- a/src/python/gudhi/simplex_tree.pyx +++ b/src/python/gudhi/simplex_tree.pyx @@ -627,6 +627,9 @@ cdef class SimplexTree: :param nb_iterations: The number of edge collapse iterations to perform. Default is 1. :type nb_iterations: int + + :note: collapse_edges method requires `Eigen <installation.html#eigen>`_ >= 3.1.0 and an exception is thrown + if this method is not available. """ # Backup old pointer cdef Simplex_tree_interface_full_featured* ptr = self.get_ptr() diff --git a/src/python/include/Simplex_tree_interface.h b/src/python/include/Simplex_tree_interface.h index baff3850..629f6083 100644 --- a/src/python/include/Simplex_tree_interface.h +++ b/src/python/include/Simplex_tree_interface.h @@ -15,7 +15,9 @@ #include <gudhi/distance_functions.h> #include <gudhi/Simplex_tree.h> #include <gudhi/Points_off_io.h> +#ifdef GUDHI_USE_EIGEN3 #include <gudhi/Flag_complex_edge_collapser.h> +#endif #include <iostream> #include <vector> @@ -162,6 +164,7 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> { } Simplex_tree_interface* collapse_edges(int nb_collapse_iteration) { +#ifdef GUDHI_USE_EIGEN3 using Filtered_edge = std::tuple<Vertex_handle, Vertex_handle, Filtration_value>; std::vector<Filtered_edge> edges; for (Simplex_handle sh : Base::skeleton_simplex_range(1)) { @@ -187,6 +190,9 @@ class Simplex_tree_interface : public Simplex_tree<SimplexTreeOptions> { collapsed_stree_ptr->insert({std::get<0>(remaining_edge), std::get<1>(remaining_edge)}, std::get<2>(remaining_edge)); } return collapsed_stree_ptr; +#else + throw std::runtime_error("Unable to collapse edges as it requires Eigen3 >= 3.1.0."); +#endif } // Iterator over the simplex tree diff --git a/src/python/test/test_simplex_tree.py b/src/python/test/test_simplex_tree.py index 3b23fa0b..a3eacaa9 100755 --- a/src/python/test/test_simplex_tree.py +++ b/src/python/test/test_simplex_tree.py @@ -8,7 +8,7 @@ - YYYY/MM Author: Description of the modification """ -from gudhi import SimplexTree +from gudhi import SimplexTree, __GUDHI_USE_EIGEN3 import pytest __author__ = "Vincent Rouvreau" @@ -353,11 +353,16 @@ def test_collapse_edges(): assert st.num_simplices() == 10 - st.collapse_edges() - assert st.num_simplices() == 9 - assert st.find([1, 3]) == False - for simplex in st.get_skeleton(0): - assert simplex[1] == 1. + if __GUDHI_USE_EIGEN3: + st.collapse_edges() + assert st.num_simplices() == 9 + assert st.find([1, 3]) == False + for simplex in st.get_skeleton(0): + assert simplex[1] == 1. + else: + # If no Eigen3, collapse_edges throws an exception + with pytest.raises(RuntimeError): + st.collapse_edges() def test_reset_filtration(): st = SimplexTree() |