From 8859128da7386955b00658ff5d71659a5de08c46 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 25 May 2021 21:29:12 +0200 Subject: First version of CubicalPersistence --- src/python/CMakeLists.txt | 1 + src/python/gudhi/sklearn/__init__.py | 0 src/python/gudhi/sklearn/cubical_persistence.py | 64 ++++++++++++++++++++++ .../test/test_sklearn_cubical_persistence.py | 35 ++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 src/python/gudhi/sklearn/__init__.py create mode 100644 src/python/gudhi/sklearn/cubical_persistence.py create mode 100644 src/python/test/test_sklearn_cubical_persistence.py (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index a1440cbc..9c19a5e7 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -262,6 +262,7 @@ if(PYTHONINTERP_FOUND) 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") + file(COPY "gudhi/sklearn" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi/") # Some files for pip package file(COPY "introduction.rst" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/") diff --git a/src/python/gudhi/sklearn/__init__.py b/src/python/gudhi/sklearn/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py new file mode 100644 index 00000000..a58fa77c --- /dev/null +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -0,0 +1,64 @@ +from .. import CubicalComplex +from sklearn.base import TransformerMixin + +class CubicalPersistence(TransformerMixin): + # Fast way to find primes and should be enough + available_primes_ = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] + """ + This is a class for computing the persistence diagrams from a cubical complex. + """ + def __init__(self, dimensions=None, persistence_dim=0, min_persistence=0): + """ + Constructor for the CubicalPersistence class. + + Parameters: + dimensions (list of int): A list of number of top dimensional cells. + persistence_dim (int): The returned persistence diagrams dimension. Default value is `0`. + min_persistence (float): The minimum persistence value to take into account (strictly greater than + `min_persistence`). Default value is `0.0`. Sets `min_persistence` to `-1.0` to see all values. + """ + self.dimensions_ = dimensions + self.persistence_dim_ = persistence_dim + + self.homology_coeff_field_ = None + for dim in self.available_primes_: + if dim > persistence_dim + 1: + self.homology_coeff_field_ = dim + break + if self.homology_coeff_field_ == None: + raise ValueError("persistence_dim must be less than 96") + + self.min_persistence_ = min_persistence + + def transform(self, X): + """ + Compute all the cubical complexes and their persistence diagrams. + + Parameters: + X (list of double OR numpy.ndarray): Cells filtration values. + + Returns: + Persistence diagrams + """ + cubical_complex = CubicalComplex(top_dimensional_cells = X, + dimensions = self.dimensions_) + cubical_complex.compute_persistence(homology_coeff_field = self.homology_coeff_field_, + min_persistence = self.min_persistence_) + self.diagrams_ = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim_) + if self.persistence_dim_ == 0: + # return all but the last, always [ 0., inf] + self.diagrams_ = self.diagrams_[:-1] + return self.diagrams_ + + def fit_transform(self, X): + """ + Compute all the cubical complexes and their persistence diagrams. + + Parameters: + X (list of double OR numpy.ndarray): Cells filtration values. + + Returns: + Persistence diagrams + """ + self.transform(X) + return self.diagrams_ diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py new file mode 100644 index 00000000..f147ffe3 --- /dev/null +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -0,0 +1,35 @@ +""" 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): Vincent Rouvreau + + Copyright (C) 2021 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +from gudhi.sklearn.cubical_persistence import CubicalPersistence +import numpy as np + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2021 Inria" +__license__ = "MIT" + +def test_simple_constructor_from_top_cells(): + cp = CubicalPersistence(persistence_dim = 0) + + # The first "0" from sklearn.datasets.load_digits() + bmp = np.array([[ 0., 0., 5., 13., 9., 1., 0., 0.], + [ 0., 0., 13., 15., 10., 15., 5., 0.], + [ 0., 3., 15., 2., 0., 11., 8., 0.], + [ 0., 4., 12., 0., 0., 8., 8., 0.], + [ 0., 5., 8., 0., 0., 9., 8., 0.], + [ 0., 4., 11., 0., 1., 12., 7., 0.], + [ 0., 2., 14., 5., 10., 12., 0., 0.], + [ 0., 0., 6., 13., 10., 0., 0., 0.]]) + + assert cp.fit_transform(bmp) == np.array([[0., 6.], [0., 8.]]) + +# from gudhi.representations import PersistenceImage +# PersistenceImage(bandwidth=50, weight=lambda x: x[1]**2, im_range=[0,256,0,256], resolution=[20, 20]) +# PI.fit_transform([diag]) \ No newline at end of file -- cgit v1.2.3 From 5b75186ace327ddc17eb6f06c0ba2485c93235ec Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 31 May 2021 12:23:29 +0200 Subject: code review + parallelization --- src/python/CMakeLists.txt | 5 +++ src/python/gudhi/sklearn/cubical_persistence.py | 52 +++++++++++----------- .../test/test_sklearn_cubical_persistence.py | 25 ++++++----- 3 files changed, 45 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index 9c19a5e7..727efbdb 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -536,6 +536,11 @@ if(PYTHONINTERP_FOUND) add_gudhi_py_test(test_dtm_rips_complex) endif() + # sklearn + if(SKLEARN_FOUND) + add_gudhi_py_test(test_sklearn_cubical_persistence) + endif() + # Set missing or not modules set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index a58fa77c..809f5d4b 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -1,13 +1,15 @@ from .. import CubicalComplex -from sklearn.base import TransformerMixin +from sklearn.base import BaseEstimator, TransformerMixin +# joblib is required by scikit-learn +from joblib import Parallel, delayed -class CubicalPersistence(TransformerMixin): +class CubicalPersistence(BaseEstimator, TransformerMixin): # Fast way to find primes and should be enough available_primes_ = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] """ This is a class for computing the persistence diagrams from a cubical complex. """ - def __init__(self, dimensions=None, persistence_dim=0, min_persistence=0): + def __init__(self, dimensions=None, persistence_dim=0, min_persistence=0, n_jobs=None): """ Constructor for the CubicalPersistence class. @@ -16,9 +18,10 @@ class CubicalPersistence(TransformerMixin): persistence_dim (int): The returned persistence diagrams dimension. Default value is `0`. min_persistence (float): The minimum persistence value to take into account (strictly greater than `min_persistence`). Default value is `0.0`. Sets `min_persistence` to `-1.0` to see all values. + n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ - self.dimensions_ = dimensions - self.persistence_dim_ = persistence_dim + self.dimensions = dimensions + self.persistence_dim = persistence_dim self.homology_coeff_field_ = None for dim in self.available_primes_: @@ -28,37 +31,36 @@ class CubicalPersistence(TransformerMixin): if self.homology_coeff_field_ == None: raise ValueError("persistence_dim must be less than 96") - self.min_persistence_ = min_persistence + self.min_persistence = min_persistence + self.n_jobs = n_jobs - def transform(self, X): + def fit(self, X, Y=None): """ - Compute all the cubical complexes and their persistence diagrams. - - Parameters: - X (list of double OR numpy.ndarray): Cells filtration values. - - Returns: - Persistence diagrams + Nothing to be done. """ - cubical_complex = CubicalComplex(top_dimensional_cells = X, - dimensions = self.dimensions_) + return self + + def __transform(self, cells): + cubical_complex = CubicalComplex(top_dimensional_cells = cells, dimensions = self.dimensions) cubical_complex.compute_persistence(homology_coeff_field = self.homology_coeff_field_, - min_persistence = self.min_persistence_) - self.diagrams_ = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim_) - if self.persistence_dim_ == 0: + min_persistence = self.min_persistence) + diagrams = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim) + if self.persistence_dim == 0: # return all but the last, always [ 0., inf] - self.diagrams_ = self.diagrams_[:-1] - return self.diagrams_ + diagrams = diagrams[:-1] + return diagrams - def fit_transform(self, X): + def transform(self, X, Y=None): """ Compute all the cubical complexes and their persistence diagrams. Parameters: - X (list of double OR numpy.ndarray): Cells filtration values. + X (list of list of double OR list of numpy.ndarray): List of cells filtration values. Returns: Persistence diagrams """ - self.transform(X) - return self.diagrams_ + + # threads is preferred as cubical construction and persistence computation releases the GIL + return Parallel(n_jobs=self.n_jobs, prefer="threads")( + delayed(self.__transform)(cells) for cells in X) diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index f147ffe3..134611c9 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -10,26 +10,27 @@ from gudhi.sklearn.cubical_persistence import CubicalPersistence import numpy as np +from sklearn import datasets __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2021 Inria" __license__ = "MIT" def test_simple_constructor_from_top_cells(): + cells = datasets.load_digits().images[0] cp = CubicalPersistence(persistence_dim = 0) + np.testing.assert_array_equal(cp._CubicalPersistence__transform(cells), + np.array([[0., 6.], [0., 8.]])) - # The first "0" from sklearn.datasets.load_digits() - bmp = np.array([[ 0., 0., 5., 13., 9., 1., 0., 0.], - [ 0., 0., 13., 15., 10., 15., 5., 0.], - [ 0., 3., 15., 2., 0., 11., 8., 0.], - [ 0., 4., 12., 0., 0., 8., 8., 0.], - [ 0., 5., 8., 0., 0., 9., 8., 0.], - [ 0., 4., 11., 0., 1., 12., 7., 0.], - [ 0., 2., 14., 5., 10., 12., 0., 0.], - [ 0., 0., 6., 13., 10., 0., 0., 0.]]) +def test_simple_constructor_from_top_cells_list(): + digits = datasets.load_digits().images[:10] + cp = CubicalPersistence(persistence_dim = 0, n_jobs=-2) - assert cp.fit_transform(bmp) == np.array([[0., 6.], [0., 8.]]) + diags = cp.fit_transform(digits) + assert len(diags) == 10 + np.testing.assert_array_equal(diags[0], + np.array([[0., 6.], [0., 8.]])) # from gudhi.representations import PersistenceImage -# PersistenceImage(bandwidth=50, weight=lambda x: x[1]**2, im_range=[0,256,0,256], resolution=[20, 20]) -# PI.fit_transform([diag]) \ No newline at end of file +# pi = PersistenceImage(bandwidth=50, weight=lambda x: x[1]**2, im_range=[0,256,0,256], resolution=[20, 20]) +# pi.fit_transform(diags) \ No newline at end of file -- cgit v1.2.3 From 4a64eef12722de3faa8ac73416aaea91658e20b6 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 1 Jun 2021 19:12:50 +0200 Subject: Add cubical scikit learn interface documentation and example --- src/python/doc/cubical_complex_sum.inc | 7 ++- src/python/doc/cubical_complex_user.rst | 58 +++++++++++++++++++--- src/python/gudhi/sklearn/cubical_persistence.py | 9 ++-- .../test/test_sklearn_cubical_persistence.py | 8 +-- 4 files changed, 58 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sum.inc b/src/python/doc/cubical_complex_sum.inc index 87db184d..2a1bde8d 100644 --- a/src/python/doc/cubical_complex_sum.inc +++ b/src/python/doc/cubical_complex_sum.inc @@ -3,12 +3,11 @@ +--------------------------------------------------------------------------+----------------------------------------------------------------------+-----------------------------+ | .. figure:: | The cubical complex represents a grid as a cell complex with | :Author: Pawel Dlotko | - | ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png | cells of all dimensions. | | - | :alt: Cubical complex representation | | :Since: GUDHI 2.0.0 | + | ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png | cells of all dimensions. | :Since: GUDHI 2.0.0 | + | :alt: Cubical complex representation | | :License: MIT | | :figclass: align-center | | | - | | | :License: MIT | - | | | | +--------------------------------------------------------------------------+----------------------------------------------------------------------+-----------------------------+ | * :doc:`cubical_complex_user` | * :doc:`cubical_complex_ref` | | | * :doc:`periodic_cubical_complex_ref` | + | | * :doc:`cubical_complex_sklearn_itf_ref` | +--------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ diff --git a/src/python/doc/cubical_complex_user.rst b/src/python/doc/cubical_complex_user.rst index 6a211347..12971243 100644 --- a/src/python/doc/cubical_complex_user.rst +++ b/src/python/doc/cubical_complex_user.rst @@ -7,14 +7,19 @@ Cubical complex user manual Definition ---------- -===================================== ===================================== ===================================== -:Author: Pawel Dlotko :Since: GUDHI PYTHON 2.0.0 :License: GPL v3 -===================================== ===================================== ===================================== +.. list-table:: + :widths: 25 50 25 + :header-rows: 0 + + * - :Author: Pawel Dlotko + - :Since: GUDHI 2.0.0 + - :License: MIT + * - :doc:`cubical_complex_user` + - * :doc:`cubical_complex_ref` + * :doc:`periodic_cubical_complex_ref` + * :doc:`cubical_complex_sklearn_itf_ref` + - -+---------------------------------------------+----------------------------------------------------------------------+ -| :doc:`cubical_complex_user` | * :doc:`cubical_complex_ref` | -| | * :doc:`periodic_cubical_complex_ref` | -+---------------------------------------------+----------------------------------------------------------------------+ The cubical complex is an example of a structured complex useful in computational mathematics (specially rigorous numerics) and image analysis. @@ -163,4 +168,41 @@ Tutorial -------- This `notebook `_ -explains how to represent sublevels sets of functions using cubical complexes. \ No newline at end of file +explains how to represent sublevels sets of functions using cubical complexes. + +Scikit-learn like interface example +----------------------------------- + +.. plot:: + :include-source: + + # Standard scientific Python imports + import matplotlib.pyplot as plt + from sklearn import datasets + + # Import cubical persistence computation scikit-learn interfaces + from gudhi.sklearn.cubical_persistence import CubicalPersistence + # Import persistence representation + from gudhi.representations import PersistenceImage, DiagramSelector + + # Get the first 10 images from scikit-learn hand digits dataset + digits = datasets.load_digits().images[:10] + targets = datasets.load_digits().target[:10] + + # TDA pipeline + cub = CubicalPersistence(persistence_dim = 0, n_jobs=-2) + diags = cub.fit_transform(digits) + + finite = DiagramSelector(use=True, point_type="finite") + finite_diags = finite.fit_transform(diags) + + persim = PersistenceImage(im_range=[0,16,0,16], resolution=[16, 16]) + pers_images = persim.fit_transform(finite_diags) + + # Display persistence images + _, axes = plt.subplots(nrows=1, ncols=10, figsize=(15, 3)) + for ax, image, label in zip(axes, pers_images, targets): + ax.set_axis_off() + ax.imshow(image.reshape(16, 16), cmap=plt.cm.gray_r, interpolation='nearest') + ax.set_title('Target: %i' % label) + plt.show() diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 809f5d4b..a7a3d036 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -5,7 +5,7 @@ from joblib import Parallel, delayed class CubicalPersistence(BaseEstimator, TransformerMixin): # Fast way to find primes and should be enough - available_primes_ = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] + _available_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] """ This is a class for computing the persistence diagrams from a cubical complex. """ @@ -24,7 +24,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): self.persistence_dim = persistence_dim self.homology_coeff_field_ = None - for dim in self.available_primes_: + for dim in self._available_primes: if dim > persistence_dim + 1: self.homology_coeff_field_ = dim break @@ -45,14 +45,11 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): cubical_complex.compute_persistence(homology_coeff_field = self.homology_coeff_field_, min_persistence = self.min_persistence) diagrams = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim) - if self.persistence_dim == 0: - # return all but the last, always [ 0., inf] - diagrams = diagrams[:-1] return diagrams def transform(self, X, Y=None): """ - Compute all the cubical complexes and their persistence diagrams. + Compute all the cubical complexes and their associated persistence diagrams. Parameters: X (list of list of double OR list of numpy.ndarray): List of cells filtration values. diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index 134611c9..c0082547 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -20,7 +20,7 @@ def test_simple_constructor_from_top_cells(): cells = datasets.load_digits().images[0] cp = CubicalPersistence(persistence_dim = 0) np.testing.assert_array_equal(cp._CubicalPersistence__transform(cells), - np.array([[0., 6.], [0., 8.]])) + np.array([[0., 6.], [0., 8.], [ 0., np.inf]])) def test_simple_constructor_from_top_cells_list(): digits = datasets.load_digits().images[:10] @@ -29,8 +29,4 @@ def test_simple_constructor_from_top_cells_list(): diags = cp.fit_transform(digits) assert len(diags) == 10 np.testing.assert_array_equal(diags[0], - np.array([[0., 6.], [0., 8.]])) - -# from gudhi.representations import PersistenceImage -# pi = PersistenceImage(bandwidth=50, weight=lambda x: x[1]**2, im_range=[0,256,0,256], resolution=[20, 20]) -# pi.fit_transform(diags) \ No newline at end of file + np.array([[0., 6.], [0., 8.], [ 0., np.inf]])) -- cgit v1.2.3 From 546b059af6c0581d06bfe9cebbe853f2f7bd4589 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 4 Jun 2021 11:56:59 +0200 Subject: Add a more relevant example inspired from https://dioscuri-tda.org/Paris_TDA_Tutorial_2021.html --- src/python/doc/cubical_complex_user.rst | 66 +++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_user.rst b/src/python/doc/cubical_complex_user.rst index 12971243..ebecb592 100644 --- a/src/python/doc/cubical_complex_user.rst +++ b/src/python/doc/cubical_complex_user.rst @@ -173,36 +173,56 @@ explains how to represent sublevels sets of functions using cubical complexes. Scikit-learn like interface example ----------------------------------- -.. plot:: - :include-source: +.. code-block:: python # Standard scientific Python imports - import matplotlib.pyplot as plt - from sklearn import datasets + import numpy as np + # Standard scikit-learn imports + from sklearn.datasets import fetch_openml + from sklearn.pipeline import Pipeline + from sklearn.model_selection import train_test_split + from sklearn.svm import SVC + from sklearn import metrics - # Import cubical persistence computation scikit-learn interfaces + # Import TDA pipeline requirements from gudhi.sklearn.cubical_persistence import CubicalPersistence - # Import persistence representation from gudhi.representations import PersistenceImage, DiagramSelector - # Get the first 10 images from scikit-learn hand digits dataset - digits = datasets.load_digits().images[:10] - targets = datasets.load_digits().target[:10] + X, y = fetch_openml('mnist_784', version=1, return_X_y=True, as_frame=False) - # TDA pipeline - cub = CubicalPersistence(persistence_dim = 0, n_jobs=-2) - diags = cub.fit_transform(digits) + # Target is: "is an eight ?" + y = (y == '8') * 1 + print('There are', np.sum(y), 'eights out of', len(y), 'numbers.') - finite = DiagramSelector(use=True, point_type="finite") - finite_diags = finite.fit_transform(diags) + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) + pipe = Pipeline([('cub_pers', CubicalPersistence(persistence_dim = 0, dimensions=[28,28], n_jobs=-2)), + ('finite_diags', DiagramSelector(use=True, point_type="finite")), + ('pers_img', PersistenceImage(bandwidth=50, + weight=lambda x: x[1]**2, + im_range=[0,256,0,256], + resolution=[20,20])), + ('svc', SVC())]) - persim = PersistenceImage(im_range=[0,16,0,16], resolution=[16, 16]) - pers_images = persim.fit_transform(finite_diags) + predicted = pipe.predict(X_test) - # Display persistence images - _, axes = plt.subplots(nrows=1, ncols=10, figsize=(15, 3)) - for ax, image, label in zip(axes, pers_images, targets): - ax.set_axis_off() - ax.imshow(image.reshape(16, 16), cmap=plt.cm.gray_r, interpolation='nearest') - ax.set_title('Target: %i' % label) - plt.show() + print(f"Classification report for TDA pipeline {pipe}:\n" + f"{metrics.classification_report(y_test, predicted)}\n") + +.. code-block:: none + + There are 6825 eights out of 70000 numbers. + Classification report for TDA pipeline Pipeline(steps=[('cub_pers', + CubicalPersistence(dimensions=[28, 28], n_jobs=-2)), + ('finite_diags', DiagramSelector(use=True)), + ('pers_img', + PersistenceImage(bandwidth=50, im_range=[0, 256, 0, 256], + weight= at 0x7f3e54137ae8>)), + ('svc', SVC())]): + precision recall f1-score support + + 0 0.97 0.99 0.98 25284 + 1 0.92 0.68 0.78 2716 + + accuracy 0.96 28000 + macro avg 0.94 0.84 0.88 28000 + weighted avg 0.96 0.96 0.96 28000 \ No newline at end of file -- cgit v1.2.3 From 8813c23e4931e9c955dd0e89547133065429ae0d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 7 Jun 2021 09:36:19 +0200 Subject: format file --- src/python/gudhi/sklearn/cubical_persistence.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index a7a3d036..f4341bf6 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -1,14 +1,17 @@ from .. import CubicalComplex from sklearn.base import BaseEstimator, TransformerMixin + # joblib is required by scikit-learn from joblib import Parallel, delayed + class CubicalPersistence(BaseEstimator, TransformerMixin): # Fast way to find primes and should be enough _available_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] """ This is a class for computing the persistence diagrams from a cubical complex. """ + def __init__(self, dimensions=None, persistence_dim=0, min_persistence=0, n_jobs=None): """ Constructor for the CubicalPersistence class. @@ -41,9 +44,10 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): return self def __transform(self, cells): - cubical_complex = CubicalComplex(top_dimensional_cells = cells, dimensions = self.dimensions) - cubical_complex.compute_persistence(homology_coeff_field = self.homology_coeff_field_, - min_persistence = self.min_persistence) + cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.dimensions) + cubical_complex.compute_persistence( + homology_coeff_field=self.homology_coeff_field_, min_persistence=self.min_persistence + ) diagrams = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim) return diagrams @@ -59,5 +63,4 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): """ # threads is preferred as cubical construction and persistence computation releases the GIL - return Parallel(n_jobs=self.n_jobs, prefer="threads")( - delayed(self.__transform)(cells) for cells in X) + return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform)(cells) for cells in X) -- cgit v1.2.3 From b7de9c211e9cfe361aa7bba9be32b88570972c38 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 7 Jun 2021 14:57:02 +0200 Subject: Improve documentation --- src/python/doc/cubical_complex_user.rst | 45 ++++++++++++++++++------- src/python/gudhi/sklearn/cubical_persistence.py | 18 ++++++++-- 2 files changed, 48 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_user.rst b/src/python/doc/cubical_complex_user.rst index ebecb592..3fd9fd84 100644 --- a/src/python/doc/cubical_complex_user.rst +++ b/src/python/doc/cubical_complex_user.rst @@ -173,10 +173,24 @@ explains how to represent sublevels sets of functions using cubical complexes. Scikit-learn like interface example ----------------------------------- +In this example, hand written digits are used as an input. +a TDA scikit-learn pipeline is constructed and is composed of: + +#. :class:`~gudhi.sklearn.cubical_persistence.CubicalPersistence` that builds a cubical complex from the inputs and + returns its persistence diagrams +#. :class:`~gudhi.representations.DiagramSelector` that removes non-finite persistence diagrams values +#. :class:`~gudhi.representations.PersistenceImage` that builds the persistence images from persistence diagrams +#. `SVC `_ which is a scikit-learn support + vector classifier. + +This ML pipeline is trained to detect if the hand written digit is an '8' or not, thanks to the fact that an '8' has +two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected components in :math:`\mathbf{H}_0`. + .. code-block:: python # Standard scientific Python imports import numpy as np + # Standard scikit-learn imports from sklearn.datasets import fetch_openml from sklearn.pipeline import Pipeline @@ -188,25 +202,32 @@ Scikit-learn like interface example from gudhi.sklearn.cubical_persistence import CubicalPersistence from gudhi.representations import PersistenceImage, DiagramSelector - X, y = fetch_openml('mnist_784', version=1, return_X_y=True, as_frame=False) + X, y = fetch_openml("mnist_784", version=1, return_X_y=True, as_frame=False) # Target is: "is an eight ?" - y = (y == '8') * 1 - print('There are', np.sum(y), 'eights out of', len(y), 'numbers.') + y = (y == "8") * 1 + print("There are", np.sum(y), "eights out of", len(y), "numbers.") X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) - pipe = Pipeline([('cub_pers', CubicalPersistence(persistence_dim = 0, dimensions=[28,28], n_jobs=-2)), - ('finite_diags', DiagramSelector(use=True, point_type="finite")), - ('pers_img', PersistenceImage(bandwidth=50, - weight=lambda x: x[1]**2, - im_range=[0,256,0,256], - resolution=[20,20])), - ('svc', SVC())]) + pipe = Pipeline( + [ + ("cub_pers", CubicalPersistence(persistence_dim=0, dimensions=[28, 28], n_jobs=-2)), + ("finite_diags", DiagramSelector(use=True, point_type="finite")), + ( + "pers_img", + PersistenceImage(bandwidth=50, weight=lambda x: x[1] ** 2, im_range=[0, 256, 0, 256], resolution=[20, 20]), + ), + ("svc", SVC()), + ] + ) + # Learn from the train subset + pipe.fit(X_train, y_train) + # Predict from the test subset predicted = pipe.predict(X_test) - print(f"Classification report for TDA pipeline {pipe}:\n" - f"{metrics.classification_report(y_test, predicted)}\n") + print(f"Classification report for TDA pipeline {pipe}:\n" f"{metrics.classification_report(y_test, predicted)}\n") + .. code-block:: none diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index f4341bf6..251e240f 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -1,3 +1,12 @@ +# 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): Vincent Rouvreau +# +# Copyright (C) 2021 Inria +# +# Modification(s): +# - YYYY/MM Author: Description of the modification + from .. import CubicalComplex from sklearn.base import BaseEstimator, TransformerMixin @@ -17,7 +26,8 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Constructor for the CubicalPersistence class. Parameters: - dimensions (list of int): A list of number of top dimensional cells. + dimensions (list of int): A list of number of top dimensional cells if cells filtration values will require + to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`) persistence_dim (int): The returned persistence diagrams dimension. Default value is `0`. min_persistence (float): The minimum persistence value to take into account (strictly greater than `min_persistence`). Default value is `0.0`. Sets `min_persistence` to `-1.0` to see all values. @@ -39,7 +49,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def fit(self, X, Y=None): """ - Nothing to be done. + Nothing to be done, but useful when included in a scikit-learn Pipeline. """ return self @@ -56,7 +66,9 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Compute all the cubical complexes and their associated persistence diagrams. Parameters: - X (list of list of double OR list of numpy.ndarray): List of cells filtration values. + X (list of list of double OR list of numpy.ndarray): List of cells filtration values that can be flatten if + dimensions is set in the constructor, or already with the correct shape in a numpy.ndarray (and + dimensions must not be set). Returns: Persistence diagrams -- cgit v1.2.3 From f2b8bbccd5cbfa2a0fbb23bdb72e965196a2c05c Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 7 Jun 2021 22:27:38 +0200 Subject: Add sklearn like reference documentation --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/python/doc/cubical_complex_sklearn_itf_ref.rst (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst new file mode 100644 index 00000000..b5c7a2e5 --- /dev/null +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -0,0 +1,20 @@ +:orphan: + +.. To get rid of WARNING: document isn't included in any toctree + +Cubical complex persistence scikit-learn like interfaces reference manual +######################################################################### + +.. list-table:: + :widths: 40 30 30 + :header-rows: 0 + + * - :Since: GUDHI 3.5.0 + - :License: MIT + - :Requires: `Scikit-learn `_ + + +.. autoclass:: gudhi.sklearn.cubical_persistence.CubicalPersistence + :members: + :special-members: __init__ + :show-inheritance: -- cgit v1.2.3 From 91d72a69f2f04676fbd671af3dc2f3040c9f1c48 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 2 Jul 2021 13:51:10 +0200 Subject: code review: bad homology_coeff_field management --- src/python/gudhi/sklearn/cubical_persistence.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 251e240f..9af683d7 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -15,13 +15,11 @@ from joblib import Parallel, delayed class CubicalPersistence(BaseEstimator, TransformerMixin): - # Fast way to find primes and should be enough - _available_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] """ This is a class for computing the persistence diagrams from a cubical complex. """ - def __init__(self, dimensions=None, persistence_dim=0, min_persistence=0, n_jobs=None): + def __init__(self, dimensions=None, persistence_dim=0, homology_coeff_field=11, min_persistence=0., n_jobs=None): """ Constructor for the CubicalPersistence class. @@ -29,21 +27,14 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): dimensions (list of int): A list of number of top dimensional cells if cells filtration values will require to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`) persistence_dim (int): The returned persistence diagrams dimension. Default value is `0`. + homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. min_persistence (float): The minimum persistence value to take into account (strictly greater than `min_persistence`). Default value is `0.0`. Sets `min_persistence` to `-1.0` to see all values. n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ self.dimensions = dimensions self.persistence_dim = persistence_dim - - self.homology_coeff_field_ = None - for dim in self._available_primes: - if dim > persistence_dim + 1: - self.homology_coeff_field_ = dim - break - if self.homology_coeff_field_ == None: - raise ValueError("persistence_dim must be less than 96") - + self.homology_coeff_field = homology_coeff_field self.min_persistence = min_persistence self.n_jobs = n_jobs @@ -56,7 +47,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def __transform(self, cells): cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.dimensions) cubical_complex.compute_persistence( - homology_coeff_field=self.homology_coeff_field_, min_persistence=self.min_persistence + homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) diagrams = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim) return diagrams -- cgit v1.2.3 From 5c35605763273cb34efe4227b6d748992e99ab09 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 9 Aug 2021 10:38:31 +0200 Subject: Make CubicalPersistence returns all dimensions. Post processing DimensionSelector can select the desired dimension --- src/python/CMakeLists.txt | 1 + src/python/doc/cubical_complex_user.rst | 2 +- src/python/gudhi/sklearn/cubical_persistence.py | 49 +++++++++++++---- src/python/gudhi/sklearn/post_processing.py | 61 ++++++++++++++++++++++ .../test/test_sklearn_cubical_persistence.py | 21 ++++++-- src/python/test/test_sklearn_post_processing.py | 48 +++++++++++++++++ 6 files changed, 167 insertions(+), 15 deletions(-) create mode 100644 src/python/gudhi/sklearn/post_processing.py create mode 100644 src/python/test/test_sklearn_post_processing.py (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index a91aab37..b38bb9aa 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -546,6 +546,7 @@ if(PYTHONINTERP_FOUND) # sklearn if(SKLEARN_FOUND) add_gudhi_py_test(test_sklearn_cubical_persistence) + add_gudhi_py_test(test_sklearn_post_processing) endif() diff --git a/src/python/doc/cubical_complex_user.rst b/src/python/doc/cubical_complex_user.rst index 3fd9fd84..a140a279 100644 --- a/src/python/doc/cubical_complex_user.rst +++ b/src/python/doc/cubical_complex_user.rst @@ -211,7 +211,7 @@ two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected com X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) pipe = Pipeline( [ - ("cub_pers", CubicalPersistence(persistence_dim=0, dimensions=[28, 28], n_jobs=-2)), + ("cub_pers", CubicalPersistence(only_this_dim=0, dimensions=[28, 28], n_jobs=-2)), ("finite_diags", DiagramSelector(use=True, point_type="finite")), ( "pers_img", diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 9af683d7..7b77000d 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -13,27 +13,44 @@ from sklearn.base import BaseEstimator, TransformerMixin # joblib is required by scikit-learn from joblib import Parallel, delayed +# Mermaid sequence diagram - https://mermaid-js.github.io/mermaid-live-editor/ +# sequenceDiagram +# USER->>CubicalPersistence: fit_transform(X) +# CubicalPersistence->>thread1: _tranform(X[0]) +# CubicalPersistence->>thread2: _tranform(X[1]) +# Note right of CubicalPersistence: ... +# thread1->>CubicalPersistence: [array( H0(X[0]) ), array( H1(X[0]) )] +# thread2->>CubicalPersistence: [array( H0(X[1]) ), array( H1(X[1]) )] +# Note right of CubicalPersistence: ... +# CubicalPersistence->>USER: [[array( H0(X[0]) ), array( H1(X[0]) )],
[array( H0(X[1]) ), array( H1(X[1]) )],
...] + class CubicalPersistence(BaseEstimator, TransformerMixin): """ This is a class for computing the persistence diagrams from a cubical complex. """ - def __init__(self, dimensions=None, persistence_dim=0, homology_coeff_field=11, min_persistence=0., n_jobs=None): + def __init__(self, dimensions=None, max_persistence_dimension=0, only_this_dim=-1, homology_coeff_field=11, min_persistence=0., n_jobs=None): """ Constructor for the CubicalPersistence class. Parameters: dimensions (list of int): A list of number of top dimensional cells if cells filtration values will require to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`) - persistence_dim (int): The returned persistence diagrams dimension. Default value is `0`. + max_persistence_dimension (int): The returned persistence diagrams maximal dimension. Default value is `0`. + Ignored if `only_this_dim` is set. + only_this_dim (int): The returned persistence diagrams dimension. If `only_this_dim` is set, + `max_persistence_dimension` will be ignored. + Short circuit the use of :class:`~gudhi.sklearn.post_processing.DimensionSelector` when only one + dimension matters. homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. min_persistence (float): The minimum persistence value to take into account (strictly greater than `min_persistence`). Default value is `0.0`. Sets `min_persistence` to `-1.0` to see all values. n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ self.dimensions = dimensions - self.persistence_dim = persistence_dim + self.max_persistence_dimension = max_persistence_dimension + self.only_this_dim = only_this_dim self.homology_coeff_field = homology_coeff_field self.min_persistence = min_persistence self.n_jobs = n_jobs @@ -49,8 +66,14 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) - diagrams = cubical_complex.persistence_intervals_in_dimension(self.persistence_dim) - return diagrams + return [cubical_complex.persistence_intervals_in_dimension(dim) for dim in range(self.max_persistence_dimension + 1)] + + def __transform_only_this_dim(self, cells): + cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.dimensions) + cubical_complex.compute_persistence( + homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence + ) + return cubical_complex.persistence_intervals_in_dimension(self.only_this_dim) def transform(self, X, Y=None): """ @@ -58,12 +81,18 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Parameters: X (list of list of double OR list of numpy.ndarray): List of cells filtration values that can be flatten if - dimensions is set in the constructor, or already with the correct shape in a numpy.ndarray (and - dimensions must not be set). + `dimensions` is set in the constructor, or already with the correct shape in a numpy.ndarray (and + `dimensions` must not be set). Returns: - Persistence diagrams + Persistence diagrams in the format: + - If `only_this_dim` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` + - else: `[[array( H0(X[0]) ), array( H1(X[0]) ), ...], [array( H0(X[1]) ), array( H1(X[1]) ), ...], ...]` """ - # threads is preferred as cubical construction and persistence computation releases the GIL - return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform)(cells) for cells in X) + if self.only_this_dim == -1: + # threads is preferred as cubical construction and persistence computation releases the GIL + return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform)(cells) for cells in X) + else: + # threads is preferred as cubical construction and persistence computation releases the GIL + return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform_only_this_dim)(cells) for cells in X) diff --git a/src/python/gudhi/sklearn/post_processing.py b/src/python/gudhi/sklearn/post_processing.py new file mode 100644 index 00000000..79276e1e --- /dev/null +++ b/src/python/gudhi/sklearn/post_processing.py @@ -0,0 +1,61 @@ +# 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): Vincent Rouvreau +# +# Copyright (C) 2021 Inria +# +# Modification(s): +# - YYYY/MM Author: Description of the modification + +from sklearn.base import BaseEstimator, TransformerMixin + +# joblib is required by scikit-learn +from joblib import Parallel, delayed + +# Mermaid sequence diagram - https://mermaid-js.github.io/mermaid-live-editor/ +# sequenceDiagram +# USER->>DimensionSelector: fit_transform(
[[array( H0(X0) ), array( H1(X0) ), ...],
[array( H0(X1) ), array( H1(X1) ), ...],
...]) +# DimensionSelector->>thread1: _transform([array( H0(X0) ), array( H1(X0) )], ...) +# DimensionSelector->>thread2: _transform([array( H0(X1) ), array( H1(X1) )], ...) +# Note right of DimensionSelector: ... +# thread1->>DimensionSelector: array( Hn(X0) ) +# thread2->>DimensionSelector: array( Hn(X1) ) +# Note right of DimensionSelector: ... +# DimensionSelector->>USER: [array( Hn(X0) ),
array( Hn(X1) ),
...] + + +class DimensionSelector(BaseEstimator, TransformerMixin): + """ + This is a class to select persistence diagrams in a specific dimension. + """ + + def __init__(self, persistence_dimension=0, n_jobs=None): + """ + Constructor for the DimensionSelector class. + + Parameters: + persistence_dimension (int): The returned persistence diagrams dimension. Default value is `0`. + """ + self.persistence_dimension = persistence_dimension + self.n_jobs = n_jobs + + def fit(self, X, Y=None): + """ + Nothing to be done, but useful when included in a scikit-learn Pipeline. + """ + return self + + def transform(self, X, Y=None): + """ + Select persistence diagrams from its dimension. + + Parameters: + X (list of list of pairs): List of list of persistence pairs, i.e. + `[[array( H0(X0) ), array( H1(X0) ), ...], [array( H0(X1) ), array( H1(X1) ), ...], ...]` + + Returns: + Persistence diagrams in a specific dimension, i.e. + `[array( Hn(X0) ), array( Hn(X1), ...]` + """ + + return [persistence[self.persistence_dimension] for persistence in X] diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index c0082547..506985f1 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -16,17 +16,30 @@ __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2021 Inria" __license__ = "MIT" +CUBICAL_PERSISTENCE_H0_IMG0 = np.array([[0., 6.], [0., 8.], [ 0., np.inf]]) + def test_simple_constructor_from_top_cells(): cells = datasets.load_digits().images[0] - cp = CubicalPersistence(persistence_dim = 0) + cp = CubicalPersistence(only_this_dim = 0) np.testing.assert_array_equal(cp._CubicalPersistence__transform(cells), - np.array([[0., 6.], [0., 8.], [ 0., np.inf]])) + [CUBICAL_PERSISTENCE_H0_IMG0]) + cp = CubicalPersistence(max_persistence_dimension = 2) + diags = cp._CubicalPersistence__transform(cells) + assert len(diags) == 3 + np.testing.assert_array_equal(diags[0], + CUBICAL_PERSISTENCE_H0_IMG0) def test_simple_constructor_from_top_cells_list(): digits = datasets.load_digits().images[:10] - cp = CubicalPersistence(persistence_dim = 0, n_jobs=-2) + cp = CubicalPersistence(only_this_dim = 0, n_jobs=-2) diags = cp.fit_transform(digits) assert len(diags) == 10 np.testing.assert_array_equal(diags[0], - np.array([[0., 6.], [0., 8.], [ 0., np.inf]])) + CUBICAL_PERSISTENCE_H0_IMG0) + + cp = CubicalPersistence(max_persistence_dimension = 1, n_jobs=-1) + diagsH0H1 = cp.fit_transform(digits) + assert len(diagsH0H1) == 10 + for idx in range(10): + np.testing.assert_array_equal(diags[idx], diagsH0H1[idx][0]) diff --git a/src/python/test/test_sklearn_post_processing.py b/src/python/test/test_sklearn_post_processing.py new file mode 100644 index 00000000..3a251d34 --- /dev/null +++ b/src/python/test/test_sklearn_post_processing.py @@ -0,0 +1,48 @@ +""" 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): Vincent Rouvreau + + Copyright (C) 2021 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +from gudhi.sklearn.post_processing import DimensionSelector +import numpy as np +import pytest + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2021 Inria" +__license__ = "MIT" + +H0_0 = np.array([0., 0.]) +H1_0 = np.array([1., 0.]) +H0_1 = np.array([0., 1.]) +H1_1 = np.array([1., 1.]) +H0_2 = np.array([0., 2.]) +H1_2 = np.array([1., 2.]) + +def test_dimension_selector(): + X = [[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]] + ds = DimensionSelector(persistence_dimension = 0, n_jobs=-2) + h0 = ds.fit_transform(X) + np.testing.assert_array_equal(h0[0], + H0_0) + np.testing.assert_array_equal(h0[1], + H0_1) + np.testing.assert_array_equal(h0[2], + H0_2) + + ds = DimensionSelector(persistence_dimension = 1, n_jobs=-1) + h1 = ds.fit_transform(X) + np.testing.assert_array_equal(h1[0], + H1_0) + np.testing.assert_array_equal(h1[1], + H1_1) + np.testing.assert_array_equal(h1[2], + H1_2) + + ds = DimensionSelector(persistence_dimension = 2, n_jobs=-2) + with pytest.raises(IndexError): + h2 = ds.fit_transform([[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]]) -- cgit v1.2.3 From e4d2b1563640331835bd3e4c08ef2f650cd49db8 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 10 Aug 2021 09:33:18 +0200 Subject: black files --- src/python/gudhi/sklearn/cubical_persistence.py | 18 ++++++++-- .../test/test_sklearn_cubical_persistence.py | 21 ++++++----- src/python/test/test_sklearn_post_processing.py | 41 ++++++++++------------ 3 files changed, 43 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 7b77000d..329c9435 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -30,7 +30,15 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): This is a class for computing the persistence diagrams from a cubical complex. """ - def __init__(self, dimensions=None, max_persistence_dimension=0, only_this_dim=-1, homology_coeff_field=11, min_persistence=0., n_jobs=None): + def __init__( + self, + dimensions=None, + max_persistence_dimension=0, + only_this_dim=-1, + homology_coeff_field=11, + min_persistence=0.0, + n_jobs=None, + ): """ Constructor for the CubicalPersistence class. @@ -66,7 +74,9 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) - return [cubical_complex.persistence_intervals_in_dimension(dim) for dim in range(self.max_persistence_dimension + 1)] + return [ + cubical_complex.persistence_intervals_in_dimension(dim) for dim in range(self.max_persistence_dimension + 1) + ] def __transform_only_this_dim(self, cells): cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.dimensions) @@ -95,4 +105,6 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform)(cells) for cells in X) else: # threads is preferred as cubical construction and persistence computation releases the GIL - return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform_only_this_dim)(cells) for cells in X) + return Parallel(n_jobs=self.n_jobs, prefer="threads")( + delayed(self.__transform_only_this_dim)(cells) for cells in X + ) diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index 506985f1..488495d1 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -16,29 +16,28 @@ __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2021 Inria" __license__ = "MIT" -CUBICAL_PERSISTENCE_H0_IMG0 = np.array([[0., 6.], [0., 8.], [ 0., np.inf]]) +CUBICAL_PERSISTENCE_H0_IMG0 = np.array([[0.0, 6.0], [0.0, 8.0], [0.0, np.inf]]) + def test_simple_constructor_from_top_cells(): cells = datasets.load_digits().images[0] - cp = CubicalPersistence(only_this_dim = 0) - np.testing.assert_array_equal(cp._CubicalPersistence__transform(cells), - [CUBICAL_PERSISTENCE_H0_IMG0]) - cp = CubicalPersistence(max_persistence_dimension = 2) + cp = CubicalPersistence(only_this_dim=0) + np.testing.assert_array_equal(cp._CubicalPersistence__transform(cells), [CUBICAL_PERSISTENCE_H0_IMG0]) + cp = CubicalPersistence(max_persistence_dimension=2) diags = cp._CubicalPersistence__transform(cells) assert len(diags) == 3 - np.testing.assert_array_equal(diags[0], - CUBICAL_PERSISTENCE_H0_IMG0) + np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) + def test_simple_constructor_from_top_cells_list(): digits = datasets.load_digits().images[:10] - cp = CubicalPersistence(only_this_dim = 0, n_jobs=-2) + cp = CubicalPersistence(only_this_dim=0, n_jobs=-2) diags = cp.fit_transform(digits) assert len(diags) == 10 - np.testing.assert_array_equal(diags[0], - CUBICAL_PERSISTENCE_H0_IMG0) + np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) - cp = CubicalPersistence(max_persistence_dimension = 1, n_jobs=-1) + cp = CubicalPersistence(max_persistence_dimension=1, n_jobs=-1) diagsH0H1 = cp.fit_transform(digits) assert len(diagsH0H1) == 10 for idx in range(10): diff --git a/src/python/test/test_sklearn_post_processing.py b/src/python/test/test_sklearn_post_processing.py index 3a251d34..60bf8162 100644 --- a/src/python/test/test_sklearn_post_processing.py +++ b/src/python/test/test_sklearn_post_processing.py @@ -16,33 +16,28 @@ __author__ = "Vincent Rouvreau" __copyright__ = "Copyright (C) 2021 Inria" __license__ = "MIT" -H0_0 = np.array([0., 0.]) -H1_0 = np.array([1., 0.]) -H0_1 = np.array([0., 1.]) -H1_1 = np.array([1., 1.]) -H0_2 = np.array([0., 2.]) -H1_2 = np.array([1., 2.]) +H0_0 = np.array([0.0, 0.0]) +H1_0 = np.array([1.0, 0.0]) +H0_1 = np.array([0.0, 1.0]) +H1_1 = np.array([1.0, 1.0]) +H0_2 = np.array([0.0, 2.0]) +H1_2 = np.array([1.0, 2.0]) + def test_dimension_selector(): X = [[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]] - ds = DimensionSelector(persistence_dimension = 0, n_jobs=-2) + ds = DimensionSelector(persistence_dimension=0, n_jobs=-2) h0 = ds.fit_transform(X) - np.testing.assert_array_equal(h0[0], - H0_0) - np.testing.assert_array_equal(h0[1], - H0_1) - np.testing.assert_array_equal(h0[2], - H0_2) - - ds = DimensionSelector(persistence_dimension = 1, n_jobs=-1) + np.testing.assert_array_equal(h0[0], H0_0) + np.testing.assert_array_equal(h0[1], H0_1) + np.testing.assert_array_equal(h0[2], H0_2) + + ds = DimensionSelector(persistence_dimension=1, n_jobs=-1) h1 = ds.fit_transform(X) - np.testing.assert_array_equal(h1[0], - H1_0) - np.testing.assert_array_equal(h1[1], - H1_1) - np.testing.assert_array_equal(h1[2], - H1_2) - - ds = DimensionSelector(persistence_dimension = 2, n_jobs=-2) + np.testing.assert_array_equal(h1[0], H1_0) + np.testing.assert_array_equal(h1[1], H1_1) + np.testing.assert_array_equal(h1[2], H1_2) + + ds = DimensionSelector(persistence_dimension=2, n_jobs=-2) with pytest.raises(IndexError): h2 = ds.fit_transform([[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]]) -- cgit v1.2.3 From d8feb8b79fc5e62929faf0bf6b671aa30d10e62d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 19 Aug 2021 09:48:33 +0200 Subject: Remove parallel from joblib as it does not improve performances --- src/python/gudhi/sklearn/post_processing.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/post_processing.py b/src/python/gudhi/sklearn/post_processing.py index 79276e1e..91d412e3 100644 --- a/src/python/gudhi/sklearn/post_processing.py +++ b/src/python/gudhi/sklearn/post_processing.py @@ -9,9 +9,6 @@ from sklearn.base import BaseEstimator, TransformerMixin -# joblib is required by scikit-learn -from joblib import Parallel, delayed - # Mermaid sequence diagram - https://mermaid-js.github.io/mermaid-live-editor/ # sequenceDiagram # USER->>DimensionSelector: fit_transform(
[[array( H0(X0) ), array( H1(X0) ), ...],
[array( H0(X1) ), array( H1(X1) ), ...],
...]) -- cgit v1.2.3 From bf13176f655d0a4d2c6fd851b22ede55b74f2d48 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 19 Aug 2021 10:55:11 +0200 Subject: No need of n_jobs --- src/python/gudhi/sklearn/post_processing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/post_processing.py b/src/python/gudhi/sklearn/post_processing.py index 91d412e3..3b12466b 100644 --- a/src/python/gudhi/sklearn/post_processing.py +++ b/src/python/gudhi/sklearn/post_processing.py @@ -26,7 +26,7 @@ class DimensionSelector(BaseEstimator, TransformerMixin): This is a class to select persistence diagrams in a specific dimension. """ - def __init__(self, persistence_dimension=0, n_jobs=None): + def __init__(self, persistence_dimension=0): """ Constructor for the DimensionSelector class. @@ -34,7 +34,6 @@ class DimensionSelector(BaseEstimator, TransformerMixin): persistence_dimension (int): The returned persistence diagrams dimension. Default value is `0`. """ self.persistence_dimension = persistence_dimension - self.n_jobs = n_jobs def fit(self, X, Y=None): """ -- cgit v1.2.3 From cad4e4bff56dee7fb05be770108775b7623648ad Mon Sep 17 00:00:00 2001 From: VincentRouvreau Date: Mon, 6 Sep 2021 15:11:09 +0200 Subject: No more parallelization as it is not faster --- src/python/test/test_sklearn_post_processing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/python/test/test_sklearn_post_processing.py b/src/python/test/test_sklearn_post_processing.py index 60bf8162..e60eadc6 100644 --- a/src/python/test/test_sklearn_post_processing.py +++ b/src/python/test/test_sklearn_post_processing.py @@ -26,18 +26,18 @@ H1_2 = np.array([1.0, 2.0]) def test_dimension_selector(): X = [[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]] - ds = DimensionSelector(persistence_dimension=0, n_jobs=-2) + ds = DimensionSelector(persistence_dimension=0) h0 = ds.fit_transform(X) np.testing.assert_array_equal(h0[0], H0_0) np.testing.assert_array_equal(h0[1], H0_1) np.testing.assert_array_equal(h0[2], H0_2) - ds = DimensionSelector(persistence_dimension=1, n_jobs=-1) + ds = DimensionSelector(persistence_dimension=1) h1 = ds.fit_transform(X) np.testing.assert_array_equal(h1[0], H1_0) np.testing.assert_array_equal(h1[1], H1_1) np.testing.assert_array_equal(h1[2], H1_2) - ds = DimensionSelector(persistence_dimension=2, n_jobs=-2) + ds = DimensionSelector(persistence_dimension=2) with pytest.raises(IndexError): h2 = ds.fit_transform([[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]]) -- cgit v1.2.3 From f55ae9257a7006fd0906a21bd3033f47b2958c6b Mon Sep 17 00:00:00 2001 From: VincentRouvreau Date: Mon, 4 Oct 2021 16:46:01 +0200 Subject: review: modification proposed from EB + HM comments fix --- src/python/CMakeLists.txt | 7 ++- src/python/doc/cubical_complex_user.rst | 5 +- src/python/gudhi/representations/preprocessing.py | 51 ++++++++++++++++++- src/python/gudhi/sklearn/cubical_persistence.py | 40 ++++++++------- src/python/gudhi/sklearn/post_processing.py | 57 ---------------------- .../test/test_representations_preprocessing.py | 39 +++++++++++++++ .../test/test_sklearn_cubical_persistence.py | 16 +++--- src/python/test/test_sklearn_post_processing.py | 43 ---------------- 8 files changed, 123 insertions(+), 135 deletions(-) delete mode 100644 src/python/gudhi/sklearn/post_processing.py create mode 100644 src/python/test/test_representations_preprocessing.py delete mode 100644 src/python/test/test_sklearn_post_processing.py (limited to 'src') diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index b38bb9aa..2ff05384 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -519,6 +519,11 @@ if(PYTHONINTERP_FOUND) add_gudhi_py_test(test_representations) endif() + # Representations preprocessing + if(SKLEARN_FOUND) + add_gudhi_py_test(test_representations_preprocessing) + endif() + # Time Delay add_gudhi_py_test(test_time_delay) @@ -546,10 +551,8 @@ if(PYTHONINTERP_FOUND) # sklearn if(SKLEARN_FOUND) add_gudhi_py_test(test_sklearn_cubical_persistence) - add_gudhi_py_test(test_sklearn_post_processing) endif() - # Set missing or not modules set(GUDHI_MODULES ${GUDHI_MODULES} "python" CACHE INTERNAL "GUDHI_MODULES") else(CYTHON_FOUND) diff --git a/src/python/doc/cubical_complex_user.rst b/src/python/doc/cubical_complex_user.rst index a140a279..e62a4395 100644 --- a/src/python/doc/cubical_complex_user.rst +++ b/src/python/doc/cubical_complex_user.rst @@ -211,7 +211,10 @@ two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected com X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) pipe = Pipeline( [ - ("cub_pers", CubicalPersistence(only_this_dim=0, dimensions=[28, 28], n_jobs=-2)), + ("cub_pers", CubicalPersistence(persistence_dimension=0, dimensions=[28, 28], n_jobs=-2)), + # Or for multiple persistence dimension computation + # ("cub_pers", CubicalPersistence(persistence_dimension=[0, 1], dimensions=[28, 28], n_jobs=-2)), + # ("H0_diags", DimensionSelector(index=0), # where index is the index in persistence_dimension array ("finite_diags", DiagramSelector(use=True, point_type="finite")), ( "pers_img", diff --git a/src/python/gudhi/representations/preprocessing.py b/src/python/gudhi/representations/preprocessing.py index a8545349..823e3954 100644 --- a/src/python/gudhi/representations/preprocessing.py +++ b/src/python/gudhi/representations/preprocessing.py @@ -1,10 +1,11 @@ # 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): Mathieu Carrière +# Author(s): Mathieu Carrière, Vincent Rouvreau # # Copyright (C) 2018-2019 Inria # # Modification(s): +# - 2021/10 Vincent Rouvreau: Add DimensionSelector # - YYYY/MM Author: Description of the modification import numpy as np @@ -363,3 +364,51 @@ class DiagramSelector(BaseEstimator, TransformerMixin): n x 2 numpy array: extracted persistence diagram. """ return self.fit_transform([diag])[0] + + +# Mermaid sequence diagram - https://mermaid-js.github.io/mermaid-live-editor/ +# sequenceDiagram +# USER->>DimensionSelector: fit_transform(
[[array( Hi(X0) ), array( Hj(X0) ), ...],
[array( Hi(X1) ), array( Hj(X1) ), ...],
...]) +# DimensionSelector->>thread1: _transform([array( Hi(X0) ), array( Hj(X0) )], ...) +# DimensionSelector->>thread2: _transform([array( Hi(X1) ), array( Hj(X1) )], ...) +# Note right of DimensionSelector: ... +# thread1->>DimensionSelector: array( Hn(X0) ) +# thread2->>DimensionSelector: array( Hn(X1) ) +# Note right of DimensionSelector: ... +# DimensionSelector->>USER: [array( Hn(X0) ),
array( Hn(X1) ),
...] + +class DimensionSelector(BaseEstimator, TransformerMixin): + """ + This is a class to select persistence diagrams in a specific dimension from its index. + """ + + def __init__(self, index=0): + """ + Constructor for the DimensionSelector class. + + Parameters: + index (int): The returned persistence diagrams dimension index. Default value is `0`. + """ + self.index = index + + def fit(self, X, Y=None): + """ + Nothing to be done, but useful when included in a scikit-learn Pipeline. + """ + return self + + def transform(self, X, Y=None): + """ + Select persistence diagrams from its dimension. + + Parameters: + X (list of list of pairs): List of list of persistence pairs, i.e. + `[[array( Hi(X0) ), array( Hj(X0) ), ...], [array( Hi(X1) ), array( Hj(X1) ), ...], ...]` + + Returns: + list of pairs: + Persistence diagrams in a specific dimension. i.e. if `index` was set to `m` and `Hn` is at index `n` of + the input, it returns `[array( Hn(X0) ), array( Hn(X1), ...]` + """ + + return [persistence[self.index] for persistence in X] diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 329c9435..454cdd07 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -33,8 +33,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def __init__( self, dimensions=None, - max_persistence_dimension=0, - only_this_dim=-1, + persistence_dimension=-1, homology_coeff_field=11, min_persistence=0.0, n_jobs=None, @@ -45,20 +44,16 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Parameters: dimensions (list of int): A list of number of top dimensional cells if cells filtration values will require to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`) - max_persistence_dimension (int): The returned persistence diagrams maximal dimension. Default value is `0`. - Ignored if `only_this_dim` is set. - only_this_dim (int): The returned persistence diagrams dimension. If `only_this_dim` is set, - `max_persistence_dimension` will be ignored. - Short circuit the use of :class:`~gudhi.sklearn.post_processing.DimensionSelector` when only one - dimension matters. + persistence_dimension (int or list of int): The returned persistence diagrams dimension(s). + Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one + dimension matters (in other words, when `persistence_dimension` is an int). homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. min_persistence (float): The minimum persistence value to take into account (strictly greater than - `min_persistence`). Default value is `0.0`. Sets `min_persistence` to `-1.0` to see all values. + `min_persistence`). Default value is `0.0`. Set `min_persistence` to `-1.0` to see all values. n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ self.dimensions = dimensions - self.max_persistence_dimension = max_persistence_dimension - self.only_this_dim = only_this_dim + self.persistence_dimension = persistence_dimension self.homology_coeff_field = homology_coeff_field self.min_persistence = min_persistence self.n_jobs = n_jobs @@ -75,7 +70,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) return [ - cubical_complex.persistence_intervals_in_dimension(dim) for dim in range(self.max_persistence_dimension + 1) + cubical_complex.persistence_intervals_in_dimension(dim) for dim in self.persistence_dimension ] def __transform_only_this_dim(self, cells): @@ -83,28 +78,31 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) - return cubical_complex.persistence_intervals_in_dimension(self.only_this_dim) + return cubical_complex.persistence_intervals_in_dimension(self.persistence_dimension) def transform(self, X, Y=None): """ Compute all the cubical complexes and their associated persistence diagrams. Parameters: - X (list of list of double OR list of numpy.ndarray): List of cells filtration values that can be flatten if - `dimensions` is set in the constructor, or already with the correct shape in a numpy.ndarray (and + X (list of list of double OR list of numpy.ndarray): List of cells filtration values that should be flatten + if `dimensions` is set in the constructor, or already with the correct shape in a numpy.ndarray (and `dimensions` must not be set). Returns: + list of pairs or list of list of pairs: Persistence diagrams in the format: - - If `only_this_dim` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` - - else: `[[array( H0(X[0]) ), array( H1(X[0]) ), ...], [array( H0(X[1]) ), array( H1(X[1]) ), ...], ...]` + - If `persistence_dimension` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` + - If `persistence_dimension` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` """ - if self.only_this_dim == -1: - # threads is preferred as cubical construction and persistence computation releases the GIL - return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform)(cells) for cells in X) - else: + # Depends on persistence_dimension is an integer or a list of integer (else case) + if isinstance(self.persistence_dimension, int): # threads is preferred as cubical construction and persistence computation releases the GIL return Parallel(n_jobs=self.n_jobs, prefer="threads")( delayed(self.__transform_only_this_dim)(cells) for cells in X ) + else: + # threads is preferred as cubical construction and persistence computation releases the GIL + return Parallel(n_jobs=self.n_jobs, prefer="threads")(delayed(self.__transform)(cells) for cells in X) + diff --git a/src/python/gudhi/sklearn/post_processing.py b/src/python/gudhi/sklearn/post_processing.py deleted file mode 100644 index 3b12466b..00000000 --- a/src/python/gudhi/sklearn/post_processing.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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): Vincent Rouvreau -# -# Copyright (C) 2021 Inria -# -# Modification(s): -# - YYYY/MM Author: Description of the modification - -from sklearn.base import BaseEstimator, TransformerMixin - -# Mermaid sequence diagram - https://mermaid-js.github.io/mermaid-live-editor/ -# sequenceDiagram -# USER->>DimensionSelector: fit_transform(
[[array( H0(X0) ), array( H1(X0) ), ...],
[array( H0(X1) ), array( H1(X1) ), ...],
...]) -# DimensionSelector->>thread1: _transform([array( H0(X0) ), array( H1(X0) )], ...) -# DimensionSelector->>thread2: _transform([array( H0(X1) ), array( H1(X1) )], ...) -# Note right of DimensionSelector: ... -# thread1->>DimensionSelector: array( Hn(X0) ) -# thread2->>DimensionSelector: array( Hn(X1) ) -# Note right of DimensionSelector: ... -# DimensionSelector->>USER: [array( Hn(X0) ),
array( Hn(X1) ),
...] - - -class DimensionSelector(BaseEstimator, TransformerMixin): - """ - This is a class to select persistence diagrams in a specific dimension. - """ - - def __init__(self, persistence_dimension=0): - """ - Constructor for the DimensionSelector class. - - Parameters: - persistence_dimension (int): The returned persistence diagrams dimension. Default value is `0`. - """ - self.persistence_dimension = persistence_dimension - - def fit(self, X, Y=None): - """ - Nothing to be done, but useful when included in a scikit-learn Pipeline. - """ - return self - - def transform(self, X, Y=None): - """ - Select persistence diagrams from its dimension. - - Parameters: - X (list of list of pairs): List of list of persistence pairs, i.e. - `[[array( H0(X0) ), array( H1(X0) ), ...], [array( H0(X1) ), array( H1(X1) ), ...], ...]` - - Returns: - Persistence diagrams in a specific dimension, i.e. - `[array( Hn(X0) ), array( Hn(X1), ...]` - """ - - return [persistence[self.persistence_dimension] for persistence in X] diff --git a/src/python/test/test_representations_preprocessing.py b/src/python/test/test_representations_preprocessing.py new file mode 100644 index 00000000..838cf30c --- /dev/null +++ b/src/python/test/test_representations_preprocessing.py @@ -0,0 +1,39 @@ +""" 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): Vincent Rouvreau + + Copyright (C) 2021 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +from gudhi.representations.preprocessing import DimensionSelector +import numpy as np +import pytest + +H0_0 = np.array([0.0, 0.0]) +H1_0 = np.array([1.0, 0.0]) +H0_1 = np.array([0.0, 1.0]) +H1_1 = np.array([1.0, 1.0]) +H0_2 = np.array([0.0, 2.0]) +H1_2 = np.array([1.0, 2.0]) + + +def test_dimension_selector(): + X = [[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]] + ds = DimensionSelector(index=0) + h0 = ds.fit_transform(X) + np.testing.assert_array_equal(h0[0], H0_0) + np.testing.assert_array_equal(h0[1], H0_1) + np.testing.assert_array_equal(h0[2], H0_2) + + ds = DimensionSelector(index=1) + h1 = ds.fit_transform(X) + np.testing.assert_array_equal(h1[0], H1_0) + np.testing.assert_array_equal(h1[1], H1_1) + np.testing.assert_array_equal(h1[2], H1_2) + + ds = DimensionSelector(index=2) + with pytest.raises(IndexError): + h2 = ds.fit_transform([[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]]) diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index 488495d1..bd728a29 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -12,32 +12,28 @@ from gudhi.sklearn.cubical_persistence import CubicalPersistence import numpy as np from sklearn import datasets -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2021 Inria" -__license__ = "MIT" - CUBICAL_PERSISTENCE_H0_IMG0 = np.array([[0.0, 6.0], [0.0, 8.0], [0.0, np.inf]]) def test_simple_constructor_from_top_cells(): cells = datasets.load_digits().images[0] - cp = CubicalPersistence(only_this_dim=0) - np.testing.assert_array_equal(cp._CubicalPersistence__transform(cells), [CUBICAL_PERSISTENCE_H0_IMG0]) - cp = CubicalPersistence(max_persistence_dimension=2) + cp = CubicalPersistence(persistence_dimension=0) + np.testing.assert_array_equal(cp._CubicalPersistence__transform_only_this_dim(cells), CUBICAL_PERSISTENCE_H0_IMG0) + cp = CubicalPersistence(persistence_dimension=[0, 2]) diags = cp._CubicalPersistence__transform(cells) - assert len(diags) == 3 + assert len(diags) == 2 np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) def test_simple_constructor_from_top_cells_list(): digits = datasets.load_digits().images[:10] - cp = CubicalPersistence(only_this_dim=0, n_jobs=-2) + cp = CubicalPersistence(persistence_dimension=0, n_jobs=-2) diags = cp.fit_transform(digits) assert len(diags) == 10 np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) - cp = CubicalPersistence(max_persistence_dimension=1, n_jobs=-1) + cp = CubicalPersistence(persistence_dimension=[0, 1], n_jobs=-1) diagsH0H1 = cp.fit_transform(digits) assert len(diagsH0H1) == 10 for idx in range(10): diff --git a/src/python/test/test_sklearn_post_processing.py b/src/python/test/test_sklearn_post_processing.py deleted file mode 100644 index e60eadc6..00000000 --- a/src/python/test/test_sklearn_post_processing.py +++ /dev/null @@ -1,43 +0,0 @@ -""" 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): Vincent Rouvreau - - Copyright (C) 2021 Inria - - Modification(s): - - YYYY/MM Author: Description of the modification -""" - -from gudhi.sklearn.post_processing import DimensionSelector -import numpy as np -import pytest - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2021 Inria" -__license__ = "MIT" - -H0_0 = np.array([0.0, 0.0]) -H1_0 = np.array([1.0, 0.0]) -H0_1 = np.array([0.0, 1.0]) -H1_1 = np.array([1.0, 1.0]) -H0_2 = np.array([0.0, 2.0]) -H1_2 = np.array([1.0, 2.0]) - - -def test_dimension_selector(): - X = [[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]] - ds = DimensionSelector(persistence_dimension=0) - h0 = ds.fit_transform(X) - np.testing.assert_array_equal(h0[0], H0_0) - np.testing.assert_array_equal(h0[1], H0_1) - np.testing.assert_array_equal(h0[2], H0_2) - - ds = DimensionSelector(persistence_dimension=1) - h1 = ds.fit_transform(X) - np.testing.assert_array_equal(h1[0], H1_0) - np.testing.assert_array_equal(h1[1], H1_1) - np.testing.assert_array_equal(h1[2], H1_2) - - ds = DimensionSelector(persistence_dimension=2) - with pytest.raises(IndexError): - h2 = ds.fit_transform([[H0_0, H1_0], [H0_1, H1_1], [H0_2, H1_2]]) -- cgit v1.2.3 From 8f14977760d05f8f08d2a7babdc197da27a6c53a Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 5 Nov 2021 11:28:42 +0100 Subject: change doc according to proposal --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 88 +++++++++++++++++++- src/python/doc/cubical_complex_sum.inc | 24 +++--- src/python/doc/cubical_complex_user.rst | 95 +--------------------- 3 files changed, 100 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index b5c7a2e5..c585f9ab 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -2,8 +2,8 @@ .. To get rid of WARNING: document isn't included in any toctree -Cubical complex persistence scikit-learn like interfaces reference manual -######################################################################### +Cubical complex persistence scikit-learn like interface +####################################################### .. list-table:: :widths: 40 30 30 @@ -13,8 +13,90 @@ Cubical complex persistence scikit-learn like interfaces reference manual - :License: MIT - :Requires: `Scikit-learn `_ +Cubical complex persistence scikit-learn like interface example +--------------------------------------------------------------- + +In this example, hand written digits are used as an input. +a TDA scikit-learn pipeline is constructed and is composed of: + +#. :class:`~gudhi.sklearn.cubical_persistence.CubicalPersistence` that builds a cubical complex from the inputs and + returns its persistence diagrams +#. :class:`~gudhi.representations.DiagramSelector` that removes non-finite persistence diagrams values +#. :class:`~gudhi.representations.PersistenceImage` that builds the persistence images from persistence diagrams +#. `SVC `_ which is a scikit-learn support + vector classifier. + +This ML pipeline is trained to detect if the hand written digit is an '8' or not, thanks to the fact that an '8' has +two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected components in :math:`\mathbf{H}_0`. + +.. code-block:: python + + # Standard scientific Python imports + import numpy as np + + # Standard scikit-learn imports + from sklearn.datasets import fetch_openml + from sklearn.pipeline import Pipeline + from sklearn.model_selection import train_test_split + from sklearn.svm import SVC + from sklearn import metrics + + # Import TDA pipeline requirements + from gudhi.sklearn.cubical_persistence import CubicalPersistence + from gudhi.representations import PersistenceImage, DiagramSelector + + X, y = fetch_openml("mnist_784", version=1, return_X_y=True, as_frame=False) + + # Target is: "is an eight ?" + y = (y == "8") * 1 + print("There are", np.sum(y), "eights out of", len(y), "numbers.") + + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) + pipe = Pipeline( + [ + ("cub_pers", CubicalPersistence(persistence_dimension=0, dimensions=[28, 28], n_jobs=-2)), + # Or for multiple persistence dimension computation + # ("cub_pers", CubicalPersistence(persistence_dimension=[0, 1], dimensions=[28, 28], n_jobs=-2)), + # ("H0_diags", DimensionSelector(index=0), # where index is the index in persistence_dimension array + ("finite_diags", DiagramSelector(use=True, point_type="finite")), + ( + "pers_img", + PersistenceImage(bandwidth=50, weight=lambda x: x[1] ** 2, im_range=[0, 256, 0, 256], resolution=[20, 20]), + ), + ("svc", SVC()), + ] + ) + + # Learn from the train subset + pipe.fit(X_train, y_train) + # Predict from the test subset + predicted = pipe.predict(X_test) + + print(f"Classification report for TDA pipeline {pipe}:\n" f"{metrics.classification_report(y_test, predicted)}\n") + +.. code-block:: none + + There are 6825 eights out of 70000 numbers. + Classification report for TDA pipeline Pipeline(steps=[('cub_pers', + CubicalPersistence(dimensions=[28, 28], n_jobs=-2)), + ('finite_diags', DiagramSelector(use=True)), + ('pers_img', + PersistenceImage(bandwidth=50, im_range=[0, 256, 0, 256], + weight= at 0x7f3e54137ae8>)), + ('svc', SVC())]): + precision recall f1-score support + + 0 0.97 0.99 0.98 25284 + 1 0.92 0.68 0.78 2716 + + accuracy 0.96 28000 + macro avg 0.94 0.84 0.88 28000 + weighted avg 0.96 0.96 0.96 28000 + +Cubical complex persistence scikit-learn like interface reference +----------------------------------------------------------------- .. autoclass:: gudhi.sklearn.cubical_persistence.CubicalPersistence :members: :special-members: __init__ - :show-inheritance: + :show-inheritance: \ No newline at end of file diff --git a/src/python/doc/cubical_complex_sum.inc b/src/python/doc/cubical_complex_sum.inc index 2a1bde8d..e2fd55bb 100644 --- a/src/python/doc/cubical_complex_sum.inc +++ b/src/python/doc/cubical_complex_sum.inc @@ -1,13 +1,17 @@ .. table:: :widths: 30 40 30 - +--------------------------------------------------------------------------+----------------------------------------------------------------------+-----------------------------+ - | .. figure:: | The cubical complex represents a grid as a cell complex with | :Author: Pawel Dlotko | - | ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png | cells of all dimensions. | :Since: GUDHI 2.0.0 | - | :alt: Cubical complex representation | | :License: MIT | - | :figclass: align-center | | | - +--------------------------------------------------------------------------+----------------------------------------------------------------------+-----------------------------+ - | * :doc:`cubical_complex_user` | * :doc:`cubical_complex_ref` | - | | * :doc:`periodic_cubical_complex_ref` | - | | * :doc:`cubical_complex_sklearn_itf_ref` | - +--------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------+ + | .. figure:: | The cubical complex represents a grid as a cell complex with | :Author: Pawel Dlotko | + | ../../doc/Bitmap_cubical_complex/Cubical_complex_representation.png | cells of all dimensions. | :Since: GUDHI 2.0.0 | + | :alt: Cubical complex representation | | :License: MIT | + | :figclass: align-center | | | + +--------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------+ + | * :doc:`cubical_complex_user` | * :doc:`cubical_complex_ref` | + | | * :doc:`periodic_cubical_complex_ref` | + +--------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------+ + | .. image:: | * :doc:`cubical_complex_sklearn_itf_ref` | :Requires: `Scikit-learn `_ | + | img/sklearn.png | | | + | :target: https://scikit-learn.org | | | + | :height: 30 | | | + +--------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------+ diff --git a/src/python/doc/cubical_complex_user.rst b/src/python/doc/cubical_complex_user.rst index e62a4395..42a23875 100644 --- a/src/python/doc/cubical_complex_user.rst +++ b/src/python/doc/cubical_complex_user.rst @@ -7,19 +7,7 @@ Cubical complex user manual Definition ---------- -.. list-table:: - :widths: 25 50 25 - :header-rows: 0 - - * - :Author: Pawel Dlotko - - :Since: GUDHI 2.0.0 - - :License: MIT - * - :doc:`cubical_complex_user` - - * :doc:`cubical_complex_ref` - * :doc:`periodic_cubical_complex_ref` - * :doc:`cubical_complex_sklearn_itf_ref` - - - +.. include:: cubical_complex_sum.inc The cubical complex is an example of a structured complex useful in computational mathematics (specially rigorous numerics) and image analysis. @@ -169,84 +157,3 @@ Tutorial This `notebook `_ explains how to represent sublevels sets of functions using cubical complexes. - -Scikit-learn like interface example ------------------------------------ - -In this example, hand written digits are used as an input. -a TDA scikit-learn pipeline is constructed and is composed of: - -#. :class:`~gudhi.sklearn.cubical_persistence.CubicalPersistence` that builds a cubical complex from the inputs and - returns its persistence diagrams -#. :class:`~gudhi.representations.DiagramSelector` that removes non-finite persistence diagrams values -#. :class:`~gudhi.representations.PersistenceImage` that builds the persistence images from persistence diagrams -#. `SVC `_ which is a scikit-learn support - vector classifier. - -This ML pipeline is trained to detect if the hand written digit is an '8' or not, thanks to the fact that an '8' has -two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected components in :math:`\mathbf{H}_0`. - -.. code-block:: python - - # Standard scientific Python imports - import numpy as np - - # Standard scikit-learn imports - from sklearn.datasets import fetch_openml - from sklearn.pipeline import Pipeline - from sklearn.model_selection import train_test_split - from sklearn.svm import SVC - from sklearn import metrics - - # Import TDA pipeline requirements - from gudhi.sklearn.cubical_persistence import CubicalPersistence - from gudhi.representations import PersistenceImage, DiagramSelector - - X, y = fetch_openml("mnist_784", version=1, return_X_y=True, as_frame=False) - - # Target is: "is an eight ?" - y = (y == "8") * 1 - print("There are", np.sum(y), "eights out of", len(y), "numbers.") - - X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) - pipe = Pipeline( - [ - ("cub_pers", CubicalPersistence(persistence_dimension=0, dimensions=[28, 28], n_jobs=-2)), - # Or for multiple persistence dimension computation - # ("cub_pers", CubicalPersistence(persistence_dimension=[0, 1], dimensions=[28, 28], n_jobs=-2)), - # ("H0_diags", DimensionSelector(index=0), # where index is the index in persistence_dimension array - ("finite_diags", DiagramSelector(use=True, point_type="finite")), - ( - "pers_img", - PersistenceImage(bandwidth=50, weight=lambda x: x[1] ** 2, im_range=[0, 256, 0, 256], resolution=[20, 20]), - ), - ("svc", SVC()), - ] - ) - - # Learn from the train subset - pipe.fit(X_train, y_train) - # Predict from the test subset - predicted = pipe.predict(X_test) - - print(f"Classification report for TDA pipeline {pipe}:\n" f"{metrics.classification_report(y_test, predicted)}\n") - - -.. code-block:: none - - There are 6825 eights out of 70000 numbers. - Classification report for TDA pipeline Pipeline(steps=[('cub_pers', - CubicalPersistence(dimensions=[28, 28], n_jobs=-2)), - ('finite_diags', DiagramSelector(use=True)), - ('pers_img', - PersistenceImage(bandwidth=50, im_range=[0, 256, 0, 256], - weight= at 0x7f3e54137ae8>)), - ('svc', SVC())]): - precision recall f1-score support - - 0 0.97 0.99 0.98 25284 - 1 0.92 0.68 0.78 2716 - - accuracy 0.96 28000 - macro avg 0.94 0.84 0.88 28000 - weighted avg 0.96 0.96 0.96 28000 \ No newline at end of file -- cgit v1.2.3 From 002487d3cd747d6ff979f33474d8bb0a7e61f44d Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 5 Nov 2021 11:30:40 +0100 Subject: add image according to proposal for doc --- src/python/doc/img/sklearn.png | Bin 0 -> 9368 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/python/doc/img/sklearn.png (limited to 'src') diff --git a/src/python/doc/img/sklearn.png b/src/python/doc/img/sklearn.png new file mode 100644 index 00000000..d1fecbbf Binary files /dev/null and b/src/python/doc/img/sklearn.png differ -- cgit v1.2.3 From b6f4e23b64b186cfd3d066b5d7c93bfe16bc9d66 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 1 Feb 2022 17:52:23 +0100 Subject: Make this table use 100% of page width for not to be displayed on 2 lines --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index c585f9ab..a57e5fbb 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -6,7 +6,7 @@ Cubical complex persistence scikit-learn like interface ####################################################### .. list-table:: - :widths: 40 30 30 + :width: 100% :header-rows: 0 * - :Since: GUDHI 3.5.0 -- cgit v1.2.3 From c34cd028cf85b69f1da17bfcef02b0cfe47a41d6 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 1 Feb 2022 18:16:59 +0100 Subject: Doc review: no double in python, float --- src/python/gudhi/representations/preprocessing.py | 6 +++--- src/python/gudhi/sklearn/cubical_persistence.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/representations/preprocessing.py b/src/python/gudhi/representations/preprocessing.py index 823e3954..bd8c2774 100644 --- a/src/python/gudhi/representations/preprocessing.py +++ b/src/python/gudhi/representations/preprocessing.py @@ -76,7 +76,7 @@ class Clamping(BaseEstimator, TransformerMixin): Constructor for the Clamping class. Parameters: - limit (double): clamping value (default np.inf). + limit (float): clamping value (default np.inf). """ self.minimum = minimum self.maximum = maximum @@ -235,7 +235,7 @@ class ProminentPoints(BaseEstimator, TransformerMixin): use (bool): whether to use the class or not (default False). location (string): either "upper" or "lower" (default "upper"). Whether to keep the points that are far away ("upper") or close ("lower") to the diagonal. num_pts (int): cardinality threshold (default 10). If location == "upper", keep the top **num_pts** points that are the farthest away from the diagonal. If location == "lower", keep the top **num_pts** points that are the closest to the diagonal. - threshold (double): distance-to-diagonal threshold (default -1). If location == "upper", keep the points that are at least at a distance **threshold** from the diagonal. If location == "lower", keep the points that are at most at a distance **threshold** from the diagonal. + threshold (float): distance-to-diagonal threshold (default -1). If location == "upper", keep the points that are at least at a distance **threshold** from the diagonal. If location == "lower", keep the points that are at most at a distance **threshold** from the diagonal. """ self.num_pts = num_pts self.threshold = threshold @@ -318,7 +318,7 @@ class DiagramSelector(BaseEstimator, TransformerMixin): Parameters: use (bool): whether to use the class or not (default False). - limit (double): second coordinate value that is the criterion for being an essential point (default numpy.inf). + limit (float): second coordinate value that is the criterion for being an essential point (default numpy.inf). point_type (string): either "finite" or "essential". The type of the points that are going to be extracted. """ self.use, self.limit, self.point_type = use, limit, point_type diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 454cdd07..27aeedf7 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -85,7 +85,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Compute all the cubical complexes and their associated persistence diagrams. Parameters: - X (list of list of double OR list of numpy.ndarray): List of cells filtration values that should be flatten + X (list of list of float OR list of numpy.ndarray): List of cells filtration values that should be flatten if `dimensions` is set in the constructor, or already with the correct shape in a numpy.ndarray (and `dimensions` must not be set). -- cgit v1.2.3 From 36457ad5c33e253d4998666a70ce94c914e596a4 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Wed, 2 Feb 2022 09:16:52 +0100 Subject: Doc review: use [sphinx docstring](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) for line not to be bold --- src/python/gudhi/sklearn/cubical_persistence.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 27aeedf7..3997bc8a 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -81,19 +81,17 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): return cubical_complex.persistence_intervals_in_dimension(self.persistence_dimension) def transform(self, X, Y=None): - """ - Compute all the cubical complexes and their associated persistence diagrams. + """Compute all the cubical complexes and their associated persistence diagrams. - Parameters: - X (list of list of float OR list of numpy.ndarray): List of cells filtration values that should be flatten - if `dimensions` is set in the constructor, or already with the correct shape in a numpy.ndarray (and - `dimensions` must not be set). + :param X: List of cells filtration values that should be flatten if `dimensions` is set in the constructor, or + already with the correct shape in a numpy.ndarray (and `dimensions` must not be set). + :type X: list of list of float OR list of numpy.ndarray + + :return: Persistence diagrams in the format: - Returns: - list of pairs or list of list of pairs: - Persistence diagrams in the format: - If `persistence_dimension` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` - If `persistence_dimension` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` + :rtype: list of pairs or list of list of pairs """ # Depends on persistence_dimension is an integer or a list of integer (else case) -- cgit v1.2.3 From af30ee3c2966d29a4e71893fa2c671aeaeb3497f Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Thu, 3 Feb 2022 10:14:41 +0100 Subject: Add flattened cells test --- src/python/test/test_sklearn_cubical_persistence.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index bd728a29..56c44db0 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -38,3 +38,13 @@ def test_simple_constructor_from_top_cells_list(): assert len(diagsH0H1) == 10 for idx in range(10): np.testing.assert_array_equal(diags[idx], diagsH0H1[idx][0]) + +def test_simple_constructor_from_flattened_cells(): + cells = datasets.load_digits().images[0] + # Not squared (extended) flatten cells + cells = np.hstack((cells, np.zeros((cells.shape[0], 2)))).flatten() + + cp = CubicalPersistence(persistence_dimension=0, dimensions=[10, 8]) + diags = cp.fit_transform([cells]) + + np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) -- cgit v1.2.3 From d4fbf78cf12488ecdf79f26ef6c05d6d1323704a Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 4 Feb 2022 09:30:13 +0100 Subject: code review: rename dimensions as 'newshape' --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 6 +++--- src/python/gudhi/sklearn/cubical_persistence.py | 14 +++++++------- src/python/test/test_sklearn_cubical_persistence.py | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index a57e5fbb..8248343b 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -54,9 +54,9 @@ two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected com X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) pipe = Pipeline( [ - ("cub_pers", CubicalPersistence(persistence_dimension=0, dimensions=[28, 28], n_jobs=-2)), + ("cub_pers", CubicalPersistence(persistence_dimension=0, newshape=[28, 28], n_jobs=-2)), # Or for multiple persistence dimension computation - # ("cub_pers", CubicalPersistence(persistence_dimension=[0, 1], dimensions=[28, 28], n_jobs=-2)), + # ("cub_pers", CubicalPersistence(persistence_dimension=[0, 1], newshape=[28, 28], n_jobs=-2)), # ("H0_diags", DimensionSelector(index=0), # where index is the index in persistence_dimension array ("finite_diags", DiagramSelector(use=True, point_type="finite")), ( @@ -78,7 +78,7 @@ two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected com There are 6825 eights out of 70000 numbers. Classification report for TDA pipeline Pipeline(steps=[('cub_pers', - CubicalPersistence(dimensions=[28, 28], n_jobs=-2)), + CubicalPersistence(newshape=[28, 28], n_jobs=-2)), ('finite_diags', DiagramSelector(use=True)), ('pers_img', PersistenceImage(bandwidth=50, im_range=[0, 256, 0, 256], diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 3997bc8a..ed56d2dd 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -32,7 +32,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def __init__( self, - dimensions=None, + newshape=None, persistence_dimension=-1, homology_coeff_field=11, min_persistence=0.0, @@ -42,7 +42,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Constructor for the CubicalPersistence class. Parameters: - dimensions (list of int): A list of number of top dimensional cells if cells filtration values will require + newshape (list of int): A list of number of top dimensional cells if cells filtration values will require to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`) persistence_dimension (int or list of int): The returned persistence diagrams dimension(s). Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one @@ -52,7 +52,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): `min_persistence`). Default value is `0.0`. Set `min_persistence` to `-1.0` to see all values. n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ - self.dimensions = dimensions + self.newshape = newshape self.persistence_dimension = persistence_dimension self.homology_coeff_field = homology_coeff_field self.min_persistence = min_persistence @@ -65,7 +65,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): return self def __transform(self, cells): - cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.dimensions) + cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.newshape) cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) @@ -74,7 +74,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): ] def __transform_only_this_dim(self, cells): - cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.dimensions) + cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.newshape) cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) @@ -83,8 +83,8 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def transform(self, X, Y=None): """Compute all the cubical complexes and their associated persistence diagrams. - :param X: List of cells filtration values that should be flatten if `dimensions` is set in the constructor, or - already with the correct shape in a numpy.ndarray (and `dimensions` must not be set). + :param X: List of cells filtration values that should be flatten if `newshape` is set in the constructor, or + already with the correct shape in a numpy.ndarray (and `newshape` must not be set). :type X: list of list of float OR list of numpy.ndarray :return: Persistence diagrams in the format: diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index 56c44db0..69b65dde 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -44,7 +44,7 @@ def test_simple_constructor_from_flattened_cells(): # Not squared (extended) flatten cells cells = np.hstack((cells, np.zeros((cells.shape[0], 2)))).flatten() - cp = CubicalPersistence(persistence_dimension=0, dimensions=[10, 8]) + cp = CubicalPersistence(persistence_dimension=0, newshape=[10, 8]) diags = cp.fit_transform([cells]) np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) -- cgit v1.2.3 From 3bfc066548fbdbd9b1dc06b39d8ccecd2ce4d0b5 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 17 Jun 2022 16:48:14 +0200 Subject: doc review: tuple instead of pair - index is 'm' and not 'n' --- src/python/gudhi/representations/preprocessing.py | 6 +++--- src/python/gudhi/sklearn/cubical_persistence.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/representations/preprocessing.py b/src/python/gudhi/representations/preprocessing.py index bd8c2774..8722e162 100644 --- a/src/python/gudhi/representations/preprocessing.py +++ b/src/python/gudhi/representations/preprocessing.py @@ -402,12 +402,12 @@ class DimensionSelector(BaseEstimator, TransformerMixin): Select persistence diagrams from its dimension. Parameters: - X (list of list of pairs): List of list of persistence pairs, i.e. + X (list of list of tuple): List of list of persistence pairs, i.e. `[[array( Hi(X0) ), array( Hj(X0) ), ...], [array( Hi(X1) ), array( Hj(X1) ), ...], ...]` Returns: - list of pairs: - Persistence diagrams in a specific dimension. i.e. if `index` was set to `m` and `Hn` is at index `n` of + list of tuple: + Persistence diagrams in a specific dimension. i.e. if `index` was set to `m` and `Hn` is at index `m` of the input, it returns `[array( Hn(X0) ), array( Hn(X1), ...]` """ diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index ed56d2dd..dc7be7f5 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -91,7 +91,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): - If `persistence_dimension` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` - If `persistence_dimension` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` - :rtype: list of pairs or list of list of pairs + :rtype: list of tuple or list of list of tuple """ # Depends on persistence_dimension is an integer or a list of integer (else case) -- cgit v1.2.3 From 8d7244b510eee0d7927c521117198ef286028acf Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Mon, 20 Jun 2022 17:07:51 +0200 Subject: code review: rename homology_dimensions argument. Use and document numpy reshape instead of cubical dimension argument --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 6 ++-- src/python/gudhi/sklearn/cubical_persistence.py | 38 ++++++++++++---------- .../test/test_sklearn_cubical_persistence.py | 21 ++++++++---- 3 files changed, 39 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index 8248343b..94862541 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -54,10 +54,10 @@ two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected com X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) pipe = Pipeline( [ - ("cub_pers", CubicalPersistence(persistence_dimension=0, newshape=[28, 28], n_jobs=-2)), + ("cub_pers", CubicalPersistence(homology_dimensions=0, newshape=[28, 28], n_jobs=-2)), # Or for multiple persistence dimension computation - # ("cub_pers", CubicalPersistence(persistence_dimension=[0, 1], newshape=[28, 28], n_jobs=-2)), - # ("H0_diags", DimensionSelector(index=0), # where index is the index in persistence_dimension array + # ("cub_pers", CubicalPersistence(homology_dimensions=[0, 1], newshape=[28, 28], n_jobs=-2)), + # ("H0_diags", DimensionSelector(index=0), # where index is the index in homology_dimensions array ("finite_diags", DiagramSelector(use=True, point_type="finite")), ( "pers_img", diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index dc7be7f5..06e9128b 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -10,6 +10,7 @@ from .. import CubicalComplex from sklearn.base import BaseEstimator, TransformerMixin +import numpy as np # joblib is required by scikit-learn from joblib import Parallel, delayed @@ -33,7 +34,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def __init__( self, newshape=None, - persistence_dimension=-1, + homology_dimensions=-1, homology_coeff_field=11, min_persistence=0.0, n_jobs=None, @@ -42,18 +43,20 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Constructor for the CubicalPersistence class. Parameters: - newshape (list of int): A list of number of top dimensional cells if cells filtration values will require - to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`) - persistence_dimension (int or list of int): The returned persistence diagrams dimension(s). + newshape (tuple of ints): If cells filtration values require to be reshaped + (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`), set `newshape` + to perform `numpy.reshape(X, newshape, order='C'` in + :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform` method. + homology_dimensions (int or list of int): The returned persistence diagrams dimension(s). Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one - dimension matters (in other words, when `persistence_dimension` is an int). + dimension matters (in other words, when `homology_dimensions` is an int). homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. min_persistence (float): The minimum persistence value to take into account (strictly greater than `min_persistence`). Default value is `0.0`. Set `min_persistence` to `-1.0` to see all values. n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ self.newshape = newshape - self.persistence_dimension = persistence_dimension + self.homology_dimensions = homology_dimensions self.homology_coeff_field = homology_coeff_field self.min_persistence = min_persistence self.n_jobs = n_jobs @@ -65,37 +68,38 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): return self def __transform(self, cells): - cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.newshape) + cubical_complex = CubicalComplex(top_dimensional_cells=cells) cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) return [ - cubical_complex.persistence_intervals_in_dimension(dim) for dim in self.persistence_dimension + cubical_complex.persistence_intervals_in_dimension(dim) for dim in self.homology_dimensions ] def __transform_only_this_dim(self, cells): - cubical_complex = CubicalComplex(top_dimensional_cells=cells, dimensions=self.newshape) + cubical_complex = CubicalComplex(top_dimensional_cells=cells) cubical_complex.compute_persistence( homology_coeff_field=self.homology_coeff_field, min_persistence=self.min_persistence ) - return cubical_complex.persistence_intervals_in_dimension(self.persistence_dimension) + return cubical_complex.persistence_intervals_in_dimension(self.homology_dimensions) def transform(self, X, Y=None): """Compute all the cubical complexes and their associated persistence diagrams. - :param X: List of cells filtration values that should be flatten if `newshape` is set in the constructor, or - already with the correct shape in a numpy.ndarray (and `newshape` must not be set). + :param X: List of cells filtration values (`numpy.reshape(X, newshape, order='C'` if `newshape` is set with a tuple of ints). :type X: list of list of float OR list of numpy.ndarray :return: Persistence diagrams in the format: - - If `persistence_dimension` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` - - If `persistence_dimension` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` + - If `homology_dimensions` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` + - If `homology_dimensions` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` :rtype: list of tuple or list of list of tuple """ - - # Depends on persistence_dimension is an integer or a list of integer (else case) - if isinstance(self.persistence_dimension, int): + if self.newshape is not None: + X = np.reshape(X, self.newshape, order='C') + + # Depends on homology_dimensions is an integer or a list of integer (else case) + if isinstance(self.homology_dimensions, int): # threads is preferred as cubical construction and persistence computation releases the GIL return Parallel(n_jobs=self.n_jobs, prefer="threads")( delayed(self.__transform_only_this_dim)(cells) for cells in X diff --git a/src/python/test/test_sklearn_cubical_persistence.py b/src/python/test/test_sklearn_cubical_persistence.py index 69b65dde..1c05a215 100644 --- a/src/python/test/test_sklearn_cubical_persistence.py +++ b/src/python/test/test_sklearn_cubical_persistence.py @@ -17,9 +17,9 @@ CUBICAL_PERSISTENCE_H0_IMG0 = np.array([[0.0, 6.0], [0.0, 8.0], [0.0, np.inf]]) def test_simple_constructor_from_top_cells(): cells = datasets.load_digits().images[0] - cp = CubicalPersistence(persistence_dimension=0) + cp = CubicalPersistence(homology_dimensions=0) np.testing.assert_array_equal(cp._CubicalPersistence__transform_only_this_dim(cells), CUBICAL_PERSISTENCE_H0_IMG0) - cp = CubicalPersistence(persistence_dimension=[0, 2]) + cp = CubicalPersistence(homology_dimensions=[0, 2]) diags = cp._CubicalPersistence__transform(cells) assert len(diags) == 2 np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) @@ -27,13 +27,13 @@ def test_simple_constructor_from_top_cells(): def test_simple_constructor_from_top_cells_list(): digits = datasets.load_digits().images[:10] - cp = CubicalPersistence(persistence_dimension=0, n_jobs=-2) + cp = CubicalPersistence(homology_dimensions=0, n_jobs=-2) diags = cp.fit_transform(digits) assert len(diags) == 10 np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) - cp = CubicalPersistence(persistence_dimension=[0, 1], n_jobs=-1) + cp = CubicalPersistence(homology_dimensions=[0, 1], n_jobs=-1) diagsH0H1 = cp.fit_transform(digits) assert len(diagsH0H1) == 10 for idx in range(10): @@ -42,9 +42,18 @@ def test_simple_constructor_from_top_cells_list(): def test_simple_constructor_from_flattened_cells(): cells = datasets.load_digits().images[0] # Not squared (extended) flatten cells - cells = np.hstack((cells, np.zeros((cells.shape[0], 2)))).flatten() + flat_cells = np.hstack((cells, np.zeros((cells.shape[0], 2)))).flatten() - cp = CubicalPersistence(persistence_dimension=0, newshape=[10, 8]) + cp = CubicalPersistence(homology_dimensions=0, newshape=[-1, 8, 10]) + diags = cp.fit_transform([flat_cells]) + + np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) + + # Not squared (extended) non-flatten cells + cells = np.hstack((cells, np.zeros((cells.shape[0], 2)))) + + # The aim of this second part of the test is to resize even if not mandatory + cp = CubicalPersistence(homology_dimensions=0, newshape=[-1, 8, 10]) diags = cp.fit_transform([cells]) np.testing.assert_array_equal(diags[0], CUBICAL_PERSISTENCE_H0_IMG0) -- cgit v1.2.3 From 106e48d65bf86aa75ec7bc317b3d008da4c23c5d Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Mon, 27 Jun 2022 07:47:14 +0200 Subject: doc review: Full path for representations gudhi module for sphinx to find the modules --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index 94862541..05ffdd0c 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -21,8 +21,8 @@ a TDA scikit-learn pipeline is constructed and is composed of: #. :class:`~gudhi.sklearn.cubical_persistence.CubicalPersistence` that builds a cubical complex from the inputs and returns its persistence diagrams -#. :class:`~gudhi.representations.DiagramSelector` that removes non-finite persistence diagrams values -#. :class:`~gudhi.representations.PersistenceImage` that builds the persistence images from persistence diagrams +#. :class:`~gudhi.representations.preprocessing.DiagramSelector` that removes non-finite persistence diagrams values +#. :class:`~gudhi.representations.vector_methods.PersistenceImage` that builds the persistence images from persistence diagrams #. `SVC `_ which is a scikit-learn support vector classifier. -- cgit v1.2.3 From 3253e504a0564bc75ffd4b1351e800593ffefd0f Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> Date: Tue, 28 Jun 2022 17:01:15 +0200 Subject: doc review: missing parenthesis Co-authored-by: Marc Glisse --- src/python/gudhi/sklearn/cubical_persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 06e9128b..7336cfee 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -45,7 +45,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Parameters: newshape (tuple of ints): If cells filtration values require to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`), set `newshape` - to perform `numpy.reshape(X, newshape, order='C'` in + to perform `numpy.reshape(X, newshape, order='C')` in :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform` method. homology_dimensions (int or list of int): The returned persistence diagrams dimension(s). Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one -- cgit v1.2.3 From cfdde35b30bdb49319b2806588de0e487aec654e Mon Sep 17 00:00:00 2001 From: Hind-M Date: Thu, 4 Aug 2022 15:43:12 +0200 Subject: Use exact option when computing edges filtrations as well in cech --- src/Cech_complex/benchmark/cech_complex_benchmark.cpp | 4 ++-- src/Cech_complex/include/gudhi/Cech_complex.h | 19 +++++++++++++------ src/Cech_complex/include/gudhi/Cech_complex_blocker.h | 7 +++---- src/Cech_complex/include/gudhi/Sphere_circumradius.h | 17 +++++++++++++++-- 4 files changed, 33 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/Cech_complex/benchmark/cech_complex_benchmark.cpp b/src/Cech_complex/benchmark/cech_complex_benchmark.cpp index a9dc5d0d..a0e727be 100644 --- a/src/Cech_complex/benchmark/cech_complex_benchmark.cpp +++ b/src/Cech_complex/benchmark/cech_complex_benchmark.cpp @@ -40,9 +40,9 @@ Simplex_tree benchmark_cech(const std::string& off_file_points, const Filtration Points_off_reader_cgal off_reader_cgal(off_file_points); Gudhi::Clock cech_clock("Cech computation"); - Cech_complex cech_complex_from_points(off_reader_cgal.get_point_cloud(), radius); + Cech_complex cech_complex_from_points(off_reader_cgal.get_point_cloud(), radius, exact); Simplex_tree cech_stree; - cech_complex_from_points.create_complex(cech_stree, dim_max, exact); + cech_complex_from_points.create_complex(cech_stree, dim_max); // ------------------------------------------ // Display information about the Cech complex diff --git a/src/Cech_complex/include/gudhi/Cech_complex.h b/src/Cech_complex/include/gudhi/Cech_complex.h index 08b7a72f..625f7c9c 100644 --- a/src/Cech_complex/include/gudhi/Cech_complex.h +++ b/src/Cech_complex/include/gudhi/Cech_complex.h @@ -62,15 +62,18 @@ class Cech_complex { * * @param[in] points Range of points where each point is defined as `kernel::Point_d`. * @param[in] max_radius Maximal radius value. + * @param[in] exact Exact filtration values computation. Not exact if `Kernel` is not CGAL::Epeck_d. + * Default is false. * */ template - Cech_complex(const InputPointRange & points, Filtration_value max_radius) : max_radius_(max_radius) { + Cech_complex(const InputPointRange & points, Filtration_value max_radius, const bool exact = false) : max_radius_(max_radius), exact_(exact) { point_cloud_.assign(std::begin(points), std::end(points)); cech_skeleton_graph_ = Gudhi::compute_proximity_graph( - point_cloud_, max_radius_, Sphere_circumradius()); + point_cloud_, max_radius_, Sphere_circumradius(exact)); } /** \brief Initializes the simplicial complex from the proximity graph and expands it until a given maximal @@ -78,19 +81,17 @@ class Cech_complex { * * @param[in] complex SimplicialComplexForCech to be created. * @param[in] dim_max graph expansion until this given maximal dimension. - * @param[in] exact Exact filtration values computation. Not exact if `Kernel` is not CGAL::Epeck_d. * @exception std::invalid_argument In debug mode, if `complex.num_vertices()` does not return 0. * */ - void create_complex(SimplicialComplexForCechComplex& complex, int dim_max, const bool exact = false) { + void create_complex(SimplicialComplexForCechComplex& complex, int dim_max) { GUDHI_CHECK(complex.num_vertices() == 0, std::invalid_argument("Cech_complex::create_complex - simplicial complex is not empty")); // insert the proximity graph in the simplicial complex complex.insert_graph(cech_skeleton_graph_); // expand the graph until dimension dim_max - complex.expansion_with_blockers(dim_max, cech_blocker(&complex, this, exact)); + complex.expansion_with_blockers(dim_max, cech_blocker(&complex, this)); } /** @return max_radius value given at construction. */ @@ -106,11 +107,17 @@ class Cech_complex { */ std::vector & get_cache() { return cache_; } + /** \brief Check exact option + * @return Exact option. + */ + const bool is_exact() { return exact_; } + private: Proximity_graph cech_skeleton_graph_; Filtration_value max_radius_; Point_cloud point_cloud_; std::vector cache_; + const bool exact_; }; } // namespace cech_complex diff --git a/src/Cech_complex/include/gudhi/Cech_complex_blocker.h b/src/Cech_complex/include/gudhi/Cech_complex_blocker.h index e7f548ba..961da1fd 100644 --- a/src/Cech_complex/include/gudhi/Cech_complex_blocker.h +++ b/src/Cech_complex/include/gudhi/Cech_complex_blocker.h @@ -104,7 +104,7 @@ class Cech_blocker { #endif // DEBUG_TRACES is_min_enclos_ball = true; #if CGAL_VERSION_NR >= 1050000000 - if(exact_) CGAL::exact(sph.second); + if(cc_ptr_->is_exact()) CGAL::exact(sph.second); #endif radius = std::sqrt(cast_to_fv(sph.second)); sc_ptr_->assign_key(sh, cc_ptr_->get_cache().size()); @@ -119,7 +119,7 @@ class Cech_blocker { } Sphere sph = get_sphere(points.cbegin(), points.cend()); #if CGAL_VERSION_NR >= 1050000000 - if(exact_) CGAL::exact(sph.second); + if(cc_ptr_->is_exact()) CGAL::exact(sph.second); #endif radius = std::sqrt(cast_to_fv(sph.second)); @@ -135,13 +135,12 @@ class Cech_blocker { } /** \internal \brief Čech complex blocker constructor. */ - Cech_blocker(SimplicialComplexForCech* sc_ptr, Cech_complex* cc_ptr, const bool exact) : sc_ptr_(sc_ptr), cc_ptr_(cc_ptr), exact_(exact) {} + Cech_blocker(SimplicialComplexForCech* sc_ptr, Cech_complex* cc_ptr) : sc_ptr_(sc_ptr), cc_ptr_(cc_ptr) {} private: SimplicialComplexForCech* sc_ptr_; Cech_complex* cc_ptr_; Kernel kernel_; - const bool exact_; }; } // namespace cech_complex diff --git a/src/Cech_complex/include/gudhi/Sphere_circumradius.h b/src/Cech_complex/include/gudhi/Sphere_circumradius.h index 790f6950..2f916c0a 100644 --- a/src/Cech_complex/include/gudhi/Sphere_circumradius.h +++ b/src/Cech_complex/include/gudhi/Sphere_circumradius.h @@ -12,6 +12,7 @@ #define SPHERE_CIRCUMRADIUS_H_ #include // for #include which is not working/compiling alone +#include // for CGAL::exact #include // for std::sqrt #include @@ -26,6 +27,7 @@ template class Sphere_circumradius { private: Kernel kernel_; + const bool exact_; public: using FT = typename Kernel::FT; using Point = typename Kernel::Point_d; @@ -42,7 +44,9 @@ class Sphere_circumradius { * */ Filtration_value operator()(const Point& point_1, const Point& point_2) const { - return std::sqrt(cast_to_fv(kernel_.squared_distance_d_object()(point_1, point_2))) / 2.; + auto squared_dist_obj = kernel_.squared_distance_d_object()(point_1, point_2); + if(exact_) CGAL::exact(squared_dist_obj); + return std::sqrt(cast_to_fv(squared_dist_obj)) / 2.; } /** \brief Circumradius of sphere passing through point cloud using CGAL. @@ -53,9 +57,18 @@ class Sphere_circumradius { * */ Filtration_value operator()(const Point_cloud& point_cloud) const { - return std::sqrt(cast_to_fv(kernel_.compute_squared_radius_d_object()(point_cloud.begin(), point_cloud.end()))); + auto squared_radius_obj = kernel_.compute_squared_radius_d_object()(point_cloud.begin(), point_cloud.end()); + if(exact_) CGAL::exact(squared_radius_obj); + return std::sqrt(cast_to_fv(squared_radius_obj)); } + /** \brief Constructor + * @param[in] exact Option for exact filtration values computation. Not exact if `Kernel` is not CGAL::Epeck_d. + * Default is false. + */ + Sphere_circumradius(const bool exact = false) : exact_(exact) {} + }; } // namespace cech_complex -- cgit v1.2.3 From e438466425ca7eda228a51a92f25e47abd8a991f Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 5 Aug 2022 14:59:30 +0200 Subject: code review: no need of default value for homology_dimensions --- src/python/gudhi/sklearn/cubical_persistence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 7336cfee..9ef48fd8 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -33,8 +33,8 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): def __init__( self, + homology_dimensions, newshape=None, - homology_dimensions=-1, homology_coeff_field=11, min_persistence=0.0, n_jobs=None, @@ -43,20 +43,20 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): Constructor for the CubicalPersistence class. Parameters: + homology_dimensions (int or list of int): The returned persistence diagrams dimension(s). + Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one + dimension matters (in other words, when `homology_dimensions` is an int). newshape (tuple of ints): If cells filtration values require to be reshaped (cf. :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform`), set `newshape` to perform `numpy.reshape(X, newshape, order='C')` in :func:`~gudhi.sklearn.cubical_persistence.CubicalPersistence.transform` method. - homology_dimensions (int or list of int): The returned persistence diagrams dimension(s). - Short circuit the use of :class:`~gudhi.representations.preprocessing.DimensionSelector` when only one - dimension matters (in other words, when `homology_dimensions` is an int). homology_coeff_field (int): The homology coefficient field. Must be a prime number. Default value is 11. min_persistence (float): The minimum persistence value to take into account (strictly greater than `min_persistence`). Default value is `0.0`. Set `min_persistence` to `-1.0` to see all values. n_jobs (int): cf. https://joblib.readthedocs.io/en/latest/generated/joblib.Parallel.html """ - self.newshape = newshape self.homology_dimensions = homology_dimensions + self.newshape = newshape self.homology_coeff_field = homology_coeff_field self.min_persistence = min_persistence self.n_jobs = n_jobs -- cgit v1.2.3 From 69198e9a00648aa5f8f38e1cef2c7bd6b7299dbb Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 5 Aug 2022 15:03:50 +0200 Subject: code review: transform rtype was not correct --- src/python/gudhi/sklearn/cubical_persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/python/gudhi/sklearn/cubical_persistence.py b/src/python/gudhi/sklearn/cubical_persistence.py index 9ef48fd8..672af278 100644 --- a/src/python/gudhi/sklearn/cubical_persistence.py +++ b/src/python/gudhi/sklearn/cubical_persistence.py @@ -93,7 +93,7 @@ class CubicalPersistence(BaseEstimator, TransformerMixin): - If `homology_dimensions` was set to `n`: `[array( Hn(X[0]) ), array( Hn(X[1]) ), ...]` - If `homology_dimensions` was set to `[i, j]`: `[[array( Hi(X[0]) ), array( Hj(X[0]) )], [array( Hi(X[1]) ), array( Hj(X[1]) )], ...]` - :rtype: list of tuple or list of list of tuple + :rtype: list of (,2) array_like or list of list of (,2) array_like """ if self.newshape is not None: X = np.reshape(X, self.newshape, order='C') -- cgit v1.2.3 From fceb0951d06df08525f032fbdf55a5c4312efb2c Mon Sep 17 00:00:00 2001 From: albert-github Date: Thu, 11 Aug 2022 14:46:43 +0200 Subject: Obsolete doxygen settings In the current master the settings - `DOT_TRANSPARENT` and `FORNULA_TRANSPARENT` are obsolete. - `DOT_FONTNAME` / `DOT_FONTSIZE` are incorporated into the new `...ATTR` settings --- src/Doxyfile.in | 63 ++++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/Doxyfile.in b/src/Doxyfile.in index 6e0e0333..0b1a8081 100644 --- a/src/Doxyfile.in +++ b/src/Doxyfile.in @@ -1452,17 +1452,6 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX @@ -2127,26 +2116,38 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = @@ -2358,18 +2359,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support -- cgit v1.2.3 From e6f04a11b32a0e9b156baa02a3f7a0a0cf611b27 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 12 Aug 2022 14:42:43 +0200 Subject: Fix version inconsistencies and #579 --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 2 +- src/python/doc/cubical_complex_sum.inc | 6 +++-- src/python/doc/differentiation_sum.inc | 4 +-- src/python/doc/persistent_cohomology_user.rst | 29 +++++++++++++--------- src/python/doc/rips_complex_sum.inc | 6 +++-- src/python/doc/rips_complex_user.rst | 8 +----- src/python/doc/simplex_tree_sum.inc | 6 +++-- 7 files changed, 33 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index 05ffdd0c..2fb8ec6a 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -9,7 +9,7 @@ Cubical complex persistence scikit-learn like interface :width: 100% :header-rows: 0 - * - :Since: GUDHI 3.5.0 + * - :Since: GUDHI 3.6.0 - :License: MIT - :Requires: `Scikit-learn `_ diff --git a/src/python/doc/cubical_complex_sum.inc b/src/python/doc/cubical_complex_sum.inc index f1cf25d4..b27843e5 100644 --- a/src/python/doc/cubical_complex_sum.inc +++ b/src/python/doc/cubical_complex_sum.inc @@ -10,8 +10,10 @@ | * :doc:`cubical_complex_user` | * :doc:`cubical_complex_ref` | | | * :doc:`periodic_cubical_complex_ref` | +--------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------+ - | | * :doc:`cubical_complex_tflow_itf_ref` | :requires: `TensorFlow `_ | - | | | | + | .. image:: | * :doc:`cubical_complex_tflow_itf_ref` | :requires: `TensorFlow `_ | + | img/tensorflow.png | | | + | :target: https://www.tensorflow.org | | | + | :height: 30 | | | +--------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------+ | .. image:: | * :doc:`cubical_complex_sklearn_itf_ref` | :Requires: `Scikit-learn `_ | | img/sklearn.png | | | diff --git a/src/python/doc/differentiation_sum.inc b/src/python/doc/differentiation_sum.inc index 3aec33df..140cf180 100644 --- a/src/python/doc/differentiation_sum.inc +++ b/src/python/doc/differentiation_sum.inc @@ -1,8 +1,8 @@ .. list-table:: - :widths: 40 30 30 + :width: 100% :header-rows: 0 - * - :Since: GUDHI 3.5.0 + * - :Since: GUDHI 3.6.0 - :License: MIT - :Requires: `TensorFlow `_ diff --git a/src/python/doc/persistent_cohomology_user.rst b/src/python/doc/persistent_cohomology_user.rst index a3f294b2..39744b95 100644 --- a/src/python/doc/persistent_cohomology_user.rst +++ b/src/python/doc/persistent_cohomology_user.rst @@ -6,19 +6,24 @@ Persistent cohomology user manual ================================= Definition ---------- -===================================== ===================================== ===================================== -:Author: Clément Maria :Since: GUDHI PYTHON 2.0.0 :License: GPL v3 -===================================== ===================================== ===================================== - -+-----------------------------------------------------------------+-----------------------------------------------------------------------+ -| :doc:`persistent_cohomology_user` | Please refer to each data structure that contains persistence | -| | feature for reference: | -| | | -| | * :doc:`simplex_tree_ref` | -| | * :doc:`cubical_complex_ref` | -| | * :doc:`periodic_cubical_complex_ref` | -+-----------------------------------------------------------------+-----------------------------------------------------------------------+ +.. list-table:: + :width: 100% + :header-rows: 0 + + * - :Author: Clément Maria + - :Since: GUDHI 2.0.0 + - :License: MIT + +.. list-table:: + :width: 100% + :header-rows: 0 + + * - :doc:`persistent_cohomology_user` + - Please refer to each data structure that contains persistence feature for reference: + * :doc:`simplex_tree_ref` + * :doc:`cubical_complex_ref` + * :doc:`periodic_cubical_complex_ref` Computation of persistent cohomology using the algorithm of :cite:`DBLP:journals/dcg/SilvaMV11` and :cite:`DBLP:conf/compgeom/DeyFW14` and the Compressed Annotation Matrix implementation of diff --git a/src/python/doc/rips_complex_sum.inc b/src/python/doc/rips_complex_sum.inc index 6931ebee..2b125e54 100644 --- a/src/python/doc/rips_complex_sum.inc +++ b/src/python/doc/rips_complex_sum.inc @@ -12,6 +12,8 @@ +----------------------------------------------------------------+------------------------------------------------------------------------+----------------------------------------------------------------------------------+ | * :doc:`rips_complex_user` | * :doc:`rips_complex_ref` | +----------------------------------------------------------------+------------------------------------------------------------------------+----------------------------------------------------------------------------------+ - | | * :doc:`rips_complex_tflow_itf_ref` | :requires: `TensorFlow `_ | - | | | | + | .. image:: | * :doc:`rips_complex_tflow_itf_ref` | :requires: `TensorFlow `_ | + | img/tensorflow.png | | | + | :target: https://www.tensorflow.org | | | + | :height: 30 | | | +----------------------------------------------------------------+------------------------------------------------------------------------+----------------------------------------------------------------------------------+ diff --git a/src/python/doc/rips_complex_user.rst b/src/python/doc/rips_complex_user.rst index 27d218d4..c41a7803 100644 --- a/src/python/doc/rips_complex_user.rst +++ b/src/python/doc/rips_complex_user.rst @@ -7,13 +7,7 @@ Rips complex user manual Definition ---------- -================================================================================ ================================ ====================== -:Authors: Clément Maria, Pawel Dlotko, Vincent Rouvreau, Marc Glisse, Yuichi Ike :Since: GUDHI 2.0.0 :License: GPL v3 -================================================================================ ================================ ====================== - -+-------------------------------------------+----------------------------------------------------------------------+ -| :doc:`rips_complex_user` | :doc:`rips_complex_ref` | -+-------------------------------------------+----------------------------------------------------------------------+ +.. include:: rips_complex_sum.inc The `Rips complex `_ is a simplicial complex that generalizes proximity (:math:`\varepsilon`-ball) graphs to higher dimensions. The vertices correspond to the input diff --git a/src/python/doc/simplex_tree_sum.inc b/src/python/doc/simplex_tree_sum.inc index 3ad1292c..6b534c9e 100644 --- a/src/python/doc/simplex_tree_sum.inc +++ b/src/python/doc/simplex_tree_sum.inc @@ -11,6 +11,8 @@ +----------------------------------------------------------------+------------------------------------------------------------------------+---------------------------------------------------------+ | * :doc:`simplex_tree_user` | * :doc:`simplex_tree_ref` | +----------------------------------------------------------------+------------------------------------------------------------------------+---------------------------------------------------------+ - | | * :doc:`ls_simplex_tree_tflow_itf_ref` | :requires: `TensorFlow `_ | - | | | | + | .. image:: | * :doc:`ls_simplex_tree_tflow_itf_ref` | :requires: `TensorFlow `_ | + | img/tensorflow.png | | | + | :target: https://www.tensorflow.org | | | + | :height: 30 | | | +----------------------------------------------------------------+------------------------------------------------------------------------+---------------------------------------------------------+ -- cgit v1.2.3 From dfcab6c8d14aab8e75040a6805f57b611c805073 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Tue, 16 Aug 2022 12:07:52 +0200 Subject: Forgotten file for 3.6.0 --- src/python/doc/img/tensorflow.png | Bin 0 -> 3846 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/python/doc/img/tensorflow.png (limited to 'src') diff --git a/src/python/doc/img/tensorflow.png b/src/python/doc/img/tensorflow.png new file mode 100644 index 00000000..a75f3f5b Binary files /dev/null and b/src/python/doc/img/tensorflow.png differ -- cgit v1.2.3 From 247a894a764dfa84cba3515c76ef7516f1b20952 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Wed, 17 Aug 2022 10:14:14 +0200 Subject: Fixing bad new shape --- src/python/doc/cubical_complex_sklearn_itf_ref.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/python/doc/cubical_complex_sklearn_itf_ref.rst b/src/python/doc/cubical_complex_sklearn_itf_ref.rst index 2fb8ec6a..90ae9ccd 100644 --- a/src/python/doc/cubical_complex_sklearn_itf_ref.rst +++ b/src/python/doc/cubical_complex_sklearn_itf_ref.rst @@ -54,9 +54,9 @@ two holes in :math:`\mathbf{H}_1`, or, like in this example, three connected com X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) pipe = Pipeline( [ - ("cub_pers", CubicalPersistence(homology_dimensions=0, newshape=[28, 28], n_jobs=-2)), + ("cub_pers", CubicalPersistence(homology_dimensions=0, newshape=[-1, 28, 28], n_jobs=-2)), # Or for multiple persistence dimension computation - # ("cub_pers", CubicalPersistence(homology_dimensions=[0, 1], newshape=[28, 28], n_jobs=-2)), + # ("cub_pers", CubicalPersistence(homology_dimensions=[0, 1], newshape=[-1, 28, 28])), # ("H0_diags", DimensionSelector(index=0), # where index is the index in homology_dimensions array ("finite_diags", DiagramSelector(use=True, point_type="finite")), ( -- cgit v1.2.3 From 26997dfccab9e8340417aaa33cf517af1ec32562 Mon Sep 17 00:00:00 2001 From: albert-github Date: Thu, 25 Aug 2022 14:01:50 +0200 Subject: Spelling corrections Correction of some obvious spelling errors --- src/Contraction/example/Rips_contraction.cpp | 2 +- src/Contraction/include/gudhi/Edge_contraction.h | 2 +- src/GudhUI/view/Viewer_instructor.h | 2 +- src/Persistence_representations/test/persistence_lanscapes_test.cpp | 2 +- src/Persistent_cohomology/include/gudhi/Persistent_cohomology.h | 2 +- src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h | 2 +- src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h | 2 +- src/cmake/modules/GUDHI_options.cmake | 4 ++-- src/python/gudhi/tensorflow/cubical_layer.py | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/Contraction/example/Rips_contraction.cpp b/src/Contraction/example/Rips_contraction.cpp index 42dd0910..547c290e 100644 --- a/src/Contraction/example/Rips_contraction.cpp +++ b/src/Contraction/example/Rips_contraction.cpp @@ -39,7 +39,7 @@ void build_rips(ComplexType& complex, double offset) { int main(int argc, char *argv[]) { if (argc != 3) { std::cerr << "Usage " << argv[0] << " ../../../data/meshes/SO3_10000.off 0.3 to load the file " << - "../../data/SO3_10000.off and contract the Rips complex built with paremeter 0.3.\n"; + "../../data/SO3_10000.off and contract the Rips complex built with parameter 0.3.\n"; return -1; } diff --git a/src/Contraction/include/gudhi/Edge_contraction.h b/src/Contraction/include/gudhi/Edge_contraction.h index 0b43c3b3..dff6dc14 100644 --- a/src/Contraction/include/gudhi/Edge_contraction.h +++ b/src/Contraction/include/gudhi/Edge_contraction.h @@ -48,7 +48,7 @@ Therefore, the simplification can be done without enumerating the set of simplic A typical application of this package is homology group computation. It is illustrated in the next figure where a Rips complex is built upon a set of high-dimensional points and simplified with edge contractions. -It has initially a big number of simplices (around 20 millions) but simplifying it to a much reduced form with only 15 vertices (and 714 simplices) takes only few seconds on a desktop machine (see the example bellow). +It has initially a big number of simplices (around 20 millions) but simplifying it to a much reduced form with only 15 vertices (and 714 simplices) takes only few seconds on a desktop machine (see the example below). One can then compute homology group with a simplicial complex having very few simplices instead of running the homology algorithm on the much bigger initial set of simplices which would take much more time and memory. diff --git a/src/GudhUI/view/Viewer_instructor.h b/src/GudhUI/view/Viewer_instructor.h index 58cbcd31..09ed102f 100644 --- a/src/GudhUI/view/Viewer_instructor.h +++ b/src/GudhUI/view/Viewer_instructor.h @@ -11,7 +11,7 @@ #ifndef VIEW_VIEWER_INSTRUCTOR_H_ #define VIEW_VIEWER_INSTRUCTOR_H_ -// todo do a viewer instructor that have directely a pointer to a QGLviewer and buffer ot not triangles +// todo do a viewer instructor that has directly a pointer to a QGLviewer and buffer ot not triangles #include #include diff --git a/src/Persistence_representations/test/persistence_lanscapes_test.cpp b/src/Persistence_representations/test/persistence_lanscapes_test.cpp index 21ef18a0..59924f16 100644 --- a/src/Persistence_representations/test/persistence_lanscapes_test.cpp +++ b/src/Persistence_representations/test/persistence_lanscapes_test.cpp @@ -238,7 +238,7 @@ if ( argc != 2 ) double integral = p.compute_integral_of_landscape(); cout << "integral : " << integral < dsets_; /* The compressed annotation matrix fields.*/ Cam cam_; - /* Dictionary establishing the correspondance between the Simplex_key of + /* Dictionary establishing the correspondence between the Simplex_key of * the root vertex in the union-find ds and the Simplex_key of the vertex which * created the connected component as a 0-dimension homology feature.*/ std::map zero_cocycles_; diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h index 8ceaa480..b4ffc756 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h @@ -1291,7 +1291,7 @@ class Skeleton_blocker_complex { typedef boost::iterator_range Complex_neighbors_vertices_range; /** - * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes trough v + * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes through v */ Complex_neighbors_vertices_range vertex_range(Vertex_handle v) const { auto begin = Complex_neighbors_vertices_iterator(this, v); diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h index a2637da3..b3bf0382 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h @@ -164,7 +164,7 @@ ComplexType> { Vertex_handle y_parent = *parent_complex.get_address( this->get_id(*y_link)); if (parent_complex.contains_edge(x_parent, y_parent)) { - // we check that there is no blocker subset of alpha passing trough x and y + // we check that there is no blocker subset of alpha passing through x and y bool new_edge = true; for (auto blocker_parent : parent_complex.const_blocker_range( x_parent)) { diff --git a/src/cmake/modules/GUDHI_options.cmake b/src/cmake/modules/GUDHI_options.cmake index 5e28c87d..8379e3c6 100644 --- a/src/cmake/modules/GUDHI_options.cmake +++ b/src/cmake/modules/GUDHI_options.cmake @@ -4,7 +4,7 @@ option(WITH_GUDHI_REMOTE_TEST "Activate/deactivate datasets fetching test which option(WITH_GUDHI_PYTHON "Activate/deactivate python module compilation and installation" ON) option(WITH_GUDHI_TEST "Activate/deactivate examples compilation and installation" ON) option(WITH_GUDHI_UTILITIES "Activate/deactivate utilities compilation and installation" ON) -option(WITH_GUDHI_THIRD_PARTY "Activate/deactivate third party libraries cmake detection. When set to OFF, it is usefull for doxygen or user_version i.e." ON) +option(WITH_GUDHI_THIRD_PARTY "Activate/deactivate third party libraries cmake detection. When set to OFF, it is useful for doxygen or user_version i.e." ON) if (NOT WITH_GUDHI_THIRD_PARTY) set (WITH_GUDHI_BENCHMARK OFF) @@ -12,4 +12,4 @@ if (NOT WITH_GUDHI_THIRD_PARTY) set (WITH_GUDHI_PYTHON OFF) set (WITH_GUDHI_TEST OFF) set (WITH_GUDHI_UTILITIES OFF) -endif() \ No newline at end of file +endif() diff --git a/src/python/gudhi/tensorflow/cubical_layer.py b/src/python/gudhi/tensorflow/cubical_layer.py index 3304e719..5df2c370 100644 --- a/src/python/gudhi/tensorflow/cubical_layer.py +++ b/src/python/gudhi/tensorflow/cubical_layer.py @@ -18,7 +18,7 @@ def _Cubical(Xflat, Xdim, dimensions, homology_coeff_field): cc = CubicalComplex(dimensions=Xdim[::-1], top_dimensional_cells=Xflat) cc.compute_persistence(homology_coeff_field=homology_coeff_field) - # Retrieve and ouput image indices/pixels corresponding to positive and negative simplices + # Retrieve and output image indices/pixels corresponding to positive and negative simplices cof_pp = cc.cofaces_of_persistence_pairs() L_cofs = [] -- cgit v1.2.3 From 359d73955c329b62510b785934f88c38b0525003 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 8 Sep 2022 16:00:06 +0200 Subject: removal of unused private members --- .../gudhi/Functions/Function_affine_plane_in_Rd.h | 101 +++++++------ .../gudhi/Functions/Function_moment_curve_in_Rd.h | 96 +++++++------ .../Integer_combination_iterator.h | 159 ++++++++++----------- 3 files changed, 180 insertions(+), 176 deletions(-) (limited to 'src') diff --git a/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h b/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h index dc6f5f90..58a9fc41 100644 --- a/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h +++ b/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h @@ -25,63 +25,62 @@ namespace coxeter_triangulation { * embedded in d-dimensional Euclidean space. */ struct Function_affine_plane_in_Rd { - /** - * \brief Value of the function at a specified point. - * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. - */ - Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { - Eigen::VectorXd result = normal_matrix_.transpose() * (p - off_); - return result; - } + /** + * \brief Value of the function at a specified point. + * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. + */ + Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { + Eigen::VectorXd result = normal_matrix_.transpose() * (p - off_); + return result; + } - /** \brief Returns the domain dimension. Same as the ambient dimension of the sphere. */ - std::size_t amb_d() const { return d_; }; + /** \brief Returns the domain dimension. Same as the ambient dimension of the sphere. */ + std::size_t amb_d() const { return d_; }; - /** \brief Returns the codomain dimension. Same as the codimension of the sphere. */ - std::size_t cod_d() const { return k_; }; + /** \brief Returns the codomain dimension. Same as the codimension of the sphere. */ + std::size_t cod_d() const { return k_; }; - /** \brief Returns a point on the affine plane. */ - Eigen::VectorXd seed() const { - Eigen::VectorXd result = off_; - return result; - } + /** \brief Returns a point on the affine plane. */ + Eigen::VectorXd seed() const { + Eigen::VectorXd result = off_; + return result; + } - /** - * \brief Constructor of the function that defines an m-dimensional implicit affine - * plane in the d-dimensional Euclidean space. - * - * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should - * correspond to the ambient dimension, the number of columns should correspond to - * the size of the normal basis (codimension). - * @param[in] offset The offset vector of the affine plane. - * The dimension of the vector should be the ambient dimension of the manifold. - */ - Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix, const Eigen::VectorXd& offset) - : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), m_(d_ - k_), off_(offset) { - normal_matrix_.colwise().normalize(); - } + /** + * \brief Constructor of the function that defines an m-dimensional implicit affine + * plane in the d-dimensional Euclidean space. + * + * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should + * correspond to the ambient dimension, the number of columns should correspond to + * the size of the normal basis (codimension). + * @param[in] offset The offset vector of the affine plane. + * The dimension of the vector should be the ambient dimension of the manifold. + */ + Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix, const Eigen::VectorXd& offset) + : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), off_(offset) { + normal_matrix_.colwise().normalize(); + } - /** - * \brief Constructor of the function that defines an m-dimensional implicit affine - * plane in the d-dimensional Euclidean space that passes through origin. - * - * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should - * correspond to the ambient dimension, the number of columns should correspond to - * the size of the normal basis (codimension). - */ - Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix) - : normal_matrix_(normal_matrix), - d_(normal_matrix.rows()), - k_(normal_matrix.cols()), - m_(d_ - k_), - off_(Eigen::VectorXd::Zero(d_)) { - normal_matrix_.colwise().normalize(); - } + /** + * \brief Constructor of the function that defines an m-dimensional implicit affine + * plane in the d-dimensional Euclidean space that passes through origin. + * + * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should + * correspond to the ambient dimension, the number of columns should correspond to + * the size of the normal basis (codimension). + */ + Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix) + : normal_matrix_(normal_matrix), + d_(normal_matrix.rows()), + k_(normal_matrix.cols()), + off_(Eigen::VectorXd::Zero(d_)) { + normal_matrix_.colwise().normalize(); + } - private: - Eigen::MatrixXd normal_matrix_; - std::size_t d_, k_, m_; - Eigen::VectorXd off_; +private: + Eigen::MatrixXd normal_matrix_; + std::size_t d_, k_; + Eigen::VectorXd off_; }; } // namespace coxeter_triangulation diff --git a/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h b/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h index 11b379f3..d44cdf70 100644 --- a/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h +++ b/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h @@ -25,51 +25,57 @@ namespace coxeter_triangulation { * in the d-dimensional Euclidean space. */ struct Function_moment_curve_in_Rd { - /** \brief Value of the function at a specified point. - * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. - */ - Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { - Eigen::VectorXd result(k_); - for (std::size_t i = 1; i < d_; ++i) result(i - 1) = p(i) - p(0) * p(i - 1); - return result; - } - - /** \brief Returns the domain (ambient) dimension.. */ - std::size_t amb_d() const { return d_; }; - - /** \brief Returns the codomain dimension. */ - std::size_t cod_d() const { return k_; }; - - /** \brief Returns a point on the moment curve. */ - Eigen::VectorXd seed() const { - Eigen::VectorXd result = Eigen::VectorXd::Zero(d_); - return result; - } - - /** - * \brief Constructor of the function that defines an implicit moment curve - * in the d-dimensional Euclidean space. - * - * @param[in] r Numerical parameter. - * @param[in] d The ambient dimension. - */ - Function_moment_curve_in_Rd(double r, std::size_t d) : m_(1), k_(d - 1), d_(d), r_(r) {} - - /** - * \brief Constructor of the function that defines an implicit moment curve - * in the d-dimensional Euclidean space. - * - * @param[in] r Numerical parameter. - * @param[in] d The ambient dimension. - * @param[in] offset The offset of the moment curve. - */ - Function_moment_curve_in_Rd(double r, std::size_t d, Eigen::VectorXd& offset) - : m_(1), k_(d - 1), d_(d), r_(r), off_(offset) {} - - private: - std::size_t m_, k_, d_; - double r_; - Eigen::VectorXd off_; +public: + /** \brief Value of the function at a specified point. + * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. + */ + Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { + Eigen::VectorXd result(k_); + for (std::size_t i = 1; i < d_; ++i) result(i - 1) = p(i) - p(0) * p(i - 1); + return result; + } + + /** \brief Returns the domain (ambient) dimension.. */ + std::size_t amb_d() const { return d_; }; + + /** \brief Returns the codomain dimension. */ + std::size_t cod_d() const { return k_; }; + + /** \brief Returns a point on the moment curve. */ + Eigen::VectorXd seed() const { + Eigen::VectorXd result = Eigen::VectorXd::Zero(d_); + return result; + } + + /** @brief Returns the radius of the moment curve. */ + double get_radius() const{ + return r_; + } + + /** + * \brief Constructor of the function that defines an implicit moment curve + * in the d-dimensional Euclidean space. + * + * @param[in] r Numerical parameter. + * @param[in] d The ambient dimension. + */ + Function_moment_curve_in_Rd(double r, std::size_t d) : k_(d - 1), d_(d), r_(r) {} + + /** + * \brief Constructor of the function that defines an implicit moment curve + * in the d-dimensional Euclidean space. + * + * @param[in] r Numerical parameter. + * @param[in] d The ambient dimension. + * @param[in] offset The offset of the moment curve. + */ + Function_moment_curve_in_Rd(double r, std::size_t d, Eigen::VectorXd& offset) + : k_(d - 1), d_(d), r_(r), off_(offset) {} + +private: + std::size_t k_, d_; + double r_; + Eigen::VectorXd off_; }; } // namespace coxeter_triangulation diff --git a/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h b/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h index 3ee73754..155995f5 100644 --- a/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h +++ b/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h @@ -25,86 +25,85 @@ typedef unsigned uint; * Based on the algorithm by Mifsud. */ class Integer_combination_iterator - : public boost::iterator_facade const, - boost::forward_traversal_tag> { - using value_t = std::vector; - - private: - friend class boost::iterator_core_access; - - bool equal(Integer_combination_iterator const& other) const { return (is_end_ && other.is_end_); } - - value_t const& dereference() const { return value_; } - - void increment() { - uint j1 = 0; - uint s = 0; - while (value_[j1] == 0 && j1 < k_) j1++; - uint j2 = j1 + 1; - while (value_[j2] == bounds_[j2]) { - if (bounds_[j2] != 0) { - s += value_[j1]; - value_[j1] = 0; - j1 = j2; - } - j2++; - } - if (j2 >= k_) { - is_end_ = true; - return; - } - s += value_[j1] - 1; - value_[j1] = 0; - value_[j2]++; - uint i = 0; - while (s >= bounds_[i]) { - value_[i] = bounds_[i]; - s -= bounds_[i]; - i++; - } - value_[i++] = s; - } - - public: - template - Integer_combination_iterator(const uint& n, const uint& k, const Bound_range& bounds) - : value_(k + 2), is_end_(n == 0 || k == 0), n_(n), k_(k) { - bounds_.reserve(k + 2); - uint sum_radices = 0; - for (auto b : bounds) { - bounds_.push_back(b); - sum_radices += b; - } - bounds_.push_back(2); - bounds_.push_back(1); - if (n > sum_radices) { - is_end_ = true; - return; - } - uint i = 0; - uint s = n; - while (s >= bounds_[i]) { - value_[i] = bounds_[i]; - s -= bounds_[i]; - i++; - } - value_[i++] = s; - - while (i < k_) value_[i++] = 0; - value_[k] = 1; - value_[k + 1] = 0; - } - - // Used for the creating an end iterator - Integer_combination_iterator() : is_end_(true), n_(0), k_(0) {} - - private: - value_t value_; // the dereference value - bool is_end_; // is true when the current integer combination is the final one - - uint n_; - uint k_; - std::vector bounds_; + : public boost::iterator_facade const, + boost::forward_traversal_tag> { + using value_t = std::vector; + +private: + friend class boost::iterator_core_access; + + bool equal(Integer_combination_iterator const& other) const { return (is_end_ && other.is_end_); } + + value_t const& dereference() const { return value_; } + + void increment() { + uint j1 = 0; + uint s = 0; + while (value_[j1] == 0 && j1 < k_) j1++; + uint j2 = j1 + 1; + while (value_[j2] == bounds_[j2]) { + if (bounds_[j2] != 0) { + s += value_[j1]; + value_[j1] = 0; + j1 = j2; + } + j2++; + } + if (j2 >= k_) { + is_end_ = true; + return; + } + s += value_[j1] - 1; + value_[j1] = 0; + value_[j2]++; + uint i = 0; + while (s >= bounds_[i]) { + value_[i] = bounds_[i]; + s -= bounds_[i]; + i++; + } + value_[i++] = s; + } + +public: + template + Integer_combination_iterator(const uint& n, const uint& k, const Bound_range& bounds) + : value_(k + 2), is_end_(n == 0 || k == 0), k_(k) { + bounds_.reserve(k + 2); + uint sum_radices = 0; + for (auto b : bounds) { + bounds_.push_back(b); + sum_radices += b; + } + bounds_.push_back(2); + bounds_.push_back(1); + if (n > sum_radices) { + is_end_ = true; + return; + } + uint i = 0; + uint s = n; + while (s >= bounds_[i]) { + value_[i] = bounds_[i]; + s -= bounds_[i]; + i++; + } + value_[i++] = s; + + while (i < k_) value_[i++] = 0; + value_[k] = 1; + value_[k + 1] = 0; + } + + // Used for the creating an end iterator + Integer_combination_iterator() : is_end_(true), k_(0) {} + +private: + value_t value_; // the dereference value + bool is_end_; // is true when the current integer combination is the final one + + uint k_; + std::vector bounds_; }; } // namespace coxeter_triangulation -- cgit v1.2.3 From d05b5ae07cca5f83cd9a94bd2a5aaf588d2eb18f Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 8 Sep 2022 17:13:42 +0200 Subject: test typo (?) fix --- src/Persistence_representations/test/persistence_heat_maps_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Persistence_representations/test/persistence_heat_maps_test.cpp b/src/Persistence_representations/test/persistence_heat_maps_test.cpp index b3240758..bf531773 100644 --- a/src/Persistence_representations/test/persistence_heat_maps_test.cpp +++ b/src/Persistence_representations/test/persistence_heat_maps_test.cpp @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(check_compute_percentage_of_active_of_heat_maps) { to_compute_percentage_of_active.push_back(&q); to_compute_percentage_of_active.push_back(&r); Persistence_heat_maps percentage_of_active; - percentage_of_active.compute_percentage_of_active(to_compute_percentage_of_active, 0.1); + percentage_of_active.compute_percentage_of_active(to_compute_percentage_of_active, 0); Persistence_heat_maps template_percentage_of_active; template_percentage_of_active.load_from_file("data/template_percentage_of_active_of_heat_maps"); -- cgit v1.2.3 From 82d7f179d7db317cfe8714bf679f50739bab1173 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Thu, 8 Sep 2022 17:14:58 +0200 Subject: fixed two -Wrange-loop-analysis warnings --- src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h | 2 +- .../include/gudhi/Skeleton_blocker_simplifiable_complex.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h index 18ae6a92..116bc779 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h @@ -150,7 +150,7 @@ struct Trie { ++s_pos; while (s_pos != s.end() && current != 0) { bool found = false; - for (const auto child : current->childs) { + for (const auto& child : current->childs) { if (child->v == *s_pos) { ++s_pos; current = child.get(); diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h index 5db9c2fd..e686aaec 100755 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h @@ -267,7 +267,7 @@ void Skeleton_blocker_complex::remove_blocker_include_in_simp template void Skeleton_blocker_complex::tip_blockers(Vertex_handle a, Vertex_handle b, std::vector & buffer) const { - for (auto const & blocker : this->const_blocker_range(a)) { + for (auto const blocker : this->const_blocker_range(a)) { Simplex beta = (*blocker); beta.remove_vertex(a); buffer.push_back(beta); -- cgit v1.2.3 From 122a9db751c392910fd09097ad50226c2a557a38 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 9 Sep 2022 11:22:06 +0200 Subject: restore indentation --- .../gudhi/Functions/Function_affine_plane_in_Rd.h | 101 ++++++------- .../gudhi/Functions/Function_moment_curve_in_Rd.h | 96 ++++++------- .../Integer_combination_iterator.h | 159 +++++++++++---------- 3 files changed, 176 insertions(+), 180 deletions(-) (limited to 'src') diff --git a/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h b/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h index 58a9fc41..dc6f5f90 100644 --- a/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h +++ b/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h @@ -25,62 +25,63 @@ namespace coxeter_triangulation { * embedded in d-dimensional Euclidean space. */ struct Function_affine_plane_in_Rd { - /** - * \brief Value of the function at a specified point. - * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. - */ - Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { - Eigen::VectorXd result = normal_matrix_.transpose() * (p - off_); - return result; - } + /** + * \brief Value of the function at a specified point. + * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. + */ + Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { + Eigen::VectorXd result = normal_matrix_.transpose() * (p - off_); + return result; + } - /** \brief Returns the domain dimension. Same as the ambient dimension of the sphere. */ - std::size_t amb_d() const { return d_; }; + /** \brief Returns the domain dimension. Same as the ambient dimension of the sphere. */ + std::size_t amb_d() const { return d_; }; - /** \brief Returns the codomain dimension. Same as the codimension of the sphere. */ - std::size_t cod_d() const { return k_; }; + /** \brief Returns the codomain dimension. Same as the codimension of the sphere. */ + std::size_t cod_d() const { return k_; }; - /** \brief Returns a point on the affine plane. */ - Eigen::VectorXd seed() const { - Eigen::VectorXd result = off_; - return result; - } + /** \brief Returns a point on the affine plane. */ + Eigen::VectorXd seed() const { + Eigen::VectorXd result = off_; + return result; + } - /** - * \brief Constructor of the function that defines an m-dimensional implicit affine - * plane in the d-dimensional Euclidean space. - * - * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should - * correspond to the ambient dimension, the number of columns should correspond to - * the size of the normal basis (codimension). - * @param[in] offset The offset vector of the affine plane. - * The dimension of the vector should be the ambient dimension of the manifold. - */ - Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix, const Eigen::VectorXd& offset) - : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), off_(offset) { - normal_matrix_.colwise().normalize(); - } + /** + * \brief Constructor of the function that defines an m-dimensional implicit affine + * plane in the d-dimensional Euclidean space. + * + * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should + * correspond to the ambient dimension, the number of columns should correspond to + * the size of the normal basis (codimension). + * @param[in] offset The offset vector of the affine plane. + * The dimension of the vector should be the ambient dimension of the manifold. + */ + Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix, const Eigen::VectorXd& offset) + : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), m_(d_ - k_), off_(offset) { + normal_matrix_.colwise().normalize(); + } - /** - * \brief Constructor of the function that defines an m-dimensional implicit affine - * plane in the d-dimensional Euclidean space that passes through origin. - * - * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should - * correspond to the ambient dimension, the number of columns should correspond to - * the size of the normal basis (codimension). - */ - Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix) - : normal_matrix_(normal_matrix), - d_(normal_matrix.rows()), - k_(normal_matrix.cols()), - off_(Eigen::VectorXd::Zero(d_)) { - normal_matrix_.colwise().normalize(); - } + /** + * \brief Constructor of the function that defines an m-dimensional implicit affine + * plane in the d-dimensional Euclidean space that passes through origin. + * + * @param[in] normal_matrix A normal matrix of the affine plane. The number of rows should + * correspond to the ambient dimension, the number of columns should correspond to + * the size of the normal basis (codimension). + */ + Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix) + : normal_matrix_(normal_matrix), + d_(normal_matrix.rows()), + k_(normal_matrix.cols()), + m_(d_ - k_), + off_(Eigen::VectorXd::Zero(d_)) { + normal_matrix_.colwise().normalize(); + } -private: - Eigen::MatrixXd normal_matrix_; - std::size_t d_, k_; - Eigen::VectorXd off_; + private: + Eigen::MatrixXd normal_matrix_; + std::size_t d_, k_, m_; + Eigen::VectorXd off_; }; } // namespace coxeter_triangulation diff --git a/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h b/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h index d44cdf70..11b379f3 100644 --- a/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h +++ b/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h @@ -25,57 +25,51 @@ namespace coxeter_triangulation { * in the d-dimensional Euclidean space. */ struct Function_moment_curve_in_Rd { -public: - /** \brief Value of the function at a specified point. - * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. - */ - Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { - Eigen::VectorXd result(k_); - for (std::size_t i = 1; i < d_; ++i) result(i - 1) = p(i) - p(0) * p(i - 1); - return result; - } - - /** \brief Returns the domain (ambient) dimension.. */ - std::size_t amb_d() const { return d_; }; - - /** \brief Returns the codomain dimension. */ - std::size_t cod_d() const { return k_; }; - - /** \brief Returns a point on the moment curve. */ - Eigen::VectorXd seed() const { - Eigen::VectorXd result = Eigen::VectorXd::Zero(d_); - return result; - } - - /** @brief Returns the radius of the moment curve. */ - double get_radius() const{ - return r_; - } - - /** - * \brief Constructor of the function that defines an implicit moment curve - * in the d-dimensional Euclidean space. - * - * @param[in] r Numerical parameter. - * @param[in] d The ambient dimension. - */ - Function_moment_curve_in_Rd(double r, std::size_t d) : k_(d - 1), d_(d), r_(r) {} - - /** - * \brief Constructor of the function that defines an implicit moment curve - * in the d-dimensional Euclidean space. - * - * @param[in] r Numerical parameter. - * @param[in] d The ambient dimension. - * @param[in] offset The offset of the moment curve. - */ - Function_moment_curve_in_Rd(double r, std::size_t d, Eigen::VectorXd& offset) - : k_(d - 1), d_(d), r_(r), off_(offset) {} - -private: - std::size_t k_, d_; - double r_; - Eigen::VectorXd off_; + /** \brief Value of the function at a specified point. + * @param[in] p The input point. The dimension needs to coincide with the ambient dimension. + */ + Eigen::VectorXd operator()(const Eigen::VectorXd& p) const { + Eigen::VectorXd result(k_); + for (std::size_t i = 1; i < d_; ++i) result(i - 1) = p(i) - p(0) * p(i - 1); + return result; + } + + /** \brief Returns the domain (ambient) dimension.. */ + std::size_t amb_d() const { return d_; }; + + /** \brief Returns the codomain dimension. */ + std::size_t cod_d() const { return k_; }; + + /** \brief Returns a point on the moment curve. */ + Eigen::VectorXd seed() const { + Eigen::VectorXd result = Eigen::VectorXd::Zero(d_); + return result; + } + + /** + * \brief Constructor of the function that defines an implicit moment curve + * in the d-dimensional Euclidean space. + * + * @param[in] r Numerical parameter. + * @param[in] d The ambient dimension. + */ + Function_moment_curve_in_Rd(double r, std::size_t d) : m_(1), k_(d - 1), d_(d), r_(r) {} + + /** + * \brief Constructor of the function that defines an implicit moment curve + * in the d-dimensional Euclidean space. + * + * @param[in] r Numerical parameter. + * @param[in] d The ambient dimension. + * @param[in] offset The offset of the moment curve. + */ + Function_moment_curve_in_Rd(double r, std::size_t d, Eigen::VectorXd& offset) + : m_(1), k_(d - 1), d_(d), r_(r), off_(offset) {} + + private: + std::size_t m_, k_, d_; + double r_; + Eigen::VectorXd off_; }; } // namespace coxeter_triangulation diff --git a/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h b/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h index 155995f5..3ee73754 100644 --- a/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h +++ b/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h @@ -25,85 +25,86 @@ typedef unsigned uint; * Based on the algorithm by Mifsud. */ class Integer_combination_iterator - : public boost::iterator_facade const, - boost::forward_traversal_tag> { - using value_t = std::vector; - -private: - friend class boost::iterator_core_access; - - bool equal(Integer_combination_iterator const& other) const { return (is_end_ && other.is_end_); } - - value_t const& dereference() const { return value_; } - - void increment() { - uint j1 = 0; - uint s = 0; - while (value_[j1] == 0 && j1 < k_) j1++; - uint j2 = j1 + 1; - while (value_[j2] == bounds_[j2]) { - if (bounds_[j2] != 0) { - s += value_[j1]; - value_[j1] = 0; - j1 = j2; - } - j2++; - } - if (j2 >= k_) { - is_end_ = true; - return; - } - s += value_[j1] - 1; - value_[j1] = 0; - value_[j2]++; - uint i = 0; - while (s >= bounds_[i]) { - value_[i] = bounds_[i]; - s -= bounds_[i]; - i++; - } - value_[i++] = s; - } - -public: - template - Integer_combination_iterator(const uint& n, const uint& k, const Bound_range& bounds) - : value_(k + 2), is_end_(n == 0 || k == 0), k_(k) { - bounds_.reserve(k + 2); - uint sum_radices = 0; - for (auto b : bounds) { - bounds_.push_back(b); - sum_radices += b; - } - bounds_.push_back(2); - bounds_.push_back(1); - if (n > sum_radices) { - is_end_ = true; - return; - } - uint i = 0; - uint s = n; - while (s >= bounds_[i]) { - value_[i] = bounds_[i]; - s -= bounds_[i]; - i++; - } - value_[i++] = s; - - while (i < k_) value_[i++] = 0; - value_[k] = 1; - value_[k + 1] = 0; - } - - // Used for the creating an end iterator - Integer_combination_iterator() : is_end_(true), k_(0) {} - -private: - value_t value_; // the dereference value - bool is_end_; // is true when the current integer combination is the final one - - uint k_; - std::vector bounds_; + : public boost::iterator_facade const, + boost::forward_traversal_tag> { + using value_t = std::vector; + + private: + friend class boost::iterator_core_access; + + bool equal(Integer_combination_iterator const& other) const { return (is_end_ && other.is_end_); } + + value_t const& dereference() const { return value_; } + + void increment() { + uint j1 = 0; + uint s = 0; + while (value_[j1] == 0 && j1 < k_) j1++; + uint j2 = j1 + 1; + while (value_[j2] == bounds_[j2]) { + if (bounds_[j2] != 0) { + s += value_[j1]; + value_[j1] = 0; + j1 = j2; + } + j2++; + } + if (j2 >= k_) { + is_end_ = true; + return; + } + s += value_[j1] - 1; + value_[j1] = 0; + value_[j2]++; + uint i = 0; + while (s >= bounds_[i]) { + value_[i] = bounds_[i]; + s -= bounds_[i]; + i++; + } + value_[i++] = s; + } + + public: + template + Integer_combination_iterator(const uint& n, const uint& k, const Bound_range& bounds) + : value_(k + 2), is_end_(n == 0 || k == 0), n_(n), k_(k) { + bounds_.reserve(k + 2); + uint sum_radices = 0; + for (auto b : bounds) { + bounds_.push_back(b); + sum_radices += b; + } + bounds_.push_back(2); + bounds_.push_back(1); + if (n > sum_radices) { + is_end_ = true; + return; + } + uint i = 0; + uint s = n; + while (s >= bounds_[i]) { + value_[i] = bounds_[i]; + s -= bounds_[i]; + i++; + } + value_[i++] = s; + + while (i < k_) value_[i++] = 0; + value_[k] = 1; + value_[k + 1] = 0; + } + + // Used for the creating an end iterator + Integer_combination_iterator() : is_end_(true), n_(0), k_(0) {} + + private: + value_t value_; // the dereference value + bool is_end_; // is true when the current integer combination is the final one + + uint n_; + uint k_; + std::vector bounds_; }; } // namespace coxeter_triangulation -- cgit v1.2.3 From 7b10950f7875793b3b2cbab15bacdeefed06d278 Mon Sep 17 00:00:00 2001 From: hschreiber Date: Fri, 9 Sep 2022 11:23:03 +0200 Subject: restore indentation part 2 --- .../include/gudhi/Functions/Function_affine_plane_in_Rd.h | 5 ++--- .../include/gudhi/Functions/Function_moment_curve_in_Rd.h | 11 ++++++++--- .../Integer_combination_iterator.h | 5 ++--- 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h b/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h index dc6f5f90..a9e2d507 100644 --- a/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h +++ b/src/Coxeter_triangulation/include/gudhi/Functions/Function_affine_plane_in_Rd.h @@ -57,7 +57,7 @@ struct Function_affine_plane_in_Rd { * The dimension of the vector should be the ambient dimension of the manifold. */ Function_affine_plane_in_Rd(const Eigen::MatrixXd& normal_matrix, const Eigen::VectorXd& offset) - : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), m_(d_ - k_), off_(offset) { + : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), off_(offset) { normal_matrix_.colwise().normalize(); } @@ -73,14 +73,13 @@ struct Function_affine_plane_in_Rd { : normal_matrix_(normal_matrix), d_(normal_matrix.rows()), k_(normal_matrix.cols()), - m_(d_ - k_), off_(Eigen::VectorXd::Zero(d_)) { normal_matrix_.colwise().normalize(); } private: Eigen::MatrixXd normal_matrix_; - std::size_t d_, k_, m_; + std::size_t d_, k_; Eigen::VectorXd off_; }; diff --git a/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h b/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h index 11b379f3..f315d794 100644 --- a/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h +++ b/src/Coxeter_triangulation/include/gudhi/Functions/Function_moment_curve_in_Rd.h @@ -46,6 +46,11 @@ struct Function_moment_curve_in_Rd { return result; } + /** @brief Returns the radius of the moment curve. */ + double get_radius() const{ + return r_; + } + /** * \brief Constructor of the function that defines an implicit moment curve * in the d-dimensional Euclidean space. @@ -53,7 +58,7 @@ struct Function_moment_curve_in_Rd { * @param[in] r Numerical parameter. * @param[in] d The ambient dimension. */ - Function_moment_curve_in_Rd(double r, std::size_t d) : m_(1), k_(d - 1), d_(d), r_(r) {} + Function_moment_curve_in_Rd(double r, std::size_t d) : k_(d - 1), d_(d), r_(r) {} /** * \brief Constructor of the function that defines an implicit moment curve @@ -64,10 +69,10 @@ struct Function_moment_curve_in_Rd { * @param[in] offset The offset of the moment curve. */ Function_moment_curve_in_Rd(double r, std::size_t d, Eigen::VectorXd& offset) - : m_(1), k_(d - 1), d_(d), r_(r), off_(offset) {} + : k_(d - 1), d_(d), r_(r), off_(offset) {} private: - std::size_t m_, k_, d_; + std::size_t k_, d_; double r_; Eigen::VectorXd off_; }; diff --git a/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h b/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h index 3ee73754..594b6fbf 100644 --- a/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h +++ b/src/Coxeter_triangulation/include/gudhi/Permutahedral_representation/Integer_combination_iterator.h @@ -68,7 +68,7 @@ class Integer_combination_iterator public: template Integer_combination_iterator(const uint& n, const uint& k, const Bound_range& bounds) - : value_(k + 2), is_end_(n == 0 || k == 0), n_(n), k_(k) { + : value_(k + 2), is_end_(n == 0 || k == 0), k_(k) { bounds_.reserve(k + 2); uint sum_radices = 0; for (auto b : bounds) { @@ -96,13 +96,12 @@ class Integer_combination_iterator } // Used for the creating an end iterator - Integer_combination_iterator() : is_end_(true), n_(0), k_(0) {} + Integer_combination_iterator() : is_end_(true), k_(0) {} private: value_t value_; // the dereference value bool is_end_; // is true when the current integer combination is the final one - uint n_; uint k_; std::vector bounds_; }; -- cgit v1.2.3 From 5f728ab258e00b6413a603e1f1082349e946a1dd Mon Sep 17 00:00:00 2001 From: hschreiber Date: Mon, 12 Sep 2022 15:07:59 +0200 Subject: self-assignment warning suppressed --- src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp b/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp index 229ae46f..f6118fe0 100644 --- a/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp +++ b/src/Simplex_tree/test/simplex_tree_ctor_and_move_unit_test.cpp @@ -98,8 +98,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(simplex_copy_constructor, Simplex_tree, list_of_te BOOST_CHECK(st == st4); BOOST_CHECK(st3 == st); +#ifdef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wself-assign-overloaded" +#endif st = st; - print_simplex_filtration(st4, "Third self copy assignment from the default Simplex_tree"); +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif + + print_simplex_filtration(st, "Third self copy assignment from the default Simplex_tree"); BOOST_CHECK(st3 == st); -- cgit v1.2.3 From d16f5256646f1ef5e9277973a9a608ada5ac7115 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 16 Sep 2022 09:35:43 +0200 Subject: Translate french comment --- .../include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h index 5abd64d7..e166c3ee 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h @@ -196,10 +196,8 @@ class Skeleton_blocker_sub_complex : public ComplexType { }; /** - * @remark remarque perte de temps a creer un nouveau simplexe a chaque fois - * alors qu'on pourrait utiliser a la place de 'addresses_sigma_in_link' - * un simplex avec des valeurs sp�ciales ComplexDS::null_vertex par exemple - * pour indiquer qu'un vertex n'appartient pas au complex + * @remark waste of time to create a new simplex each time when we could use instead of addresses_sigma_in_link a + * simplex with special values (ComplexDS::null_vertex i.e.) to indicate that a vertex does not belong to the complex. */ template bool proper_face_in_union( -- cgit v1.2.3 From fdfed55bd323b378c48100f651db8447f4285ea7 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 16 Sep 2022 09:57:07 +0200 Subject: Force light mode --- src/Doxyfile.in | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/Doxyfile.in b/src/Doxyfile.in index 0b1a8081..1ec190d9 100644 --- a/src/Doxyfile.in +++ b/src/Doxyfile.in @@ -1143,6 +1143,11 @@ HTML_EXTRA_STYLESHEET = @GUDHI_DOXYGEN_COMMON_DOC_PATH@/stylesheet.css HTML_EXTRA_FILES = +# Default here is AUTO_LIGHT which means "Automatically set the mode according +# to the user preference, use light mode if no preference is set". +# Force it to LIGHT (white), as the rest of the documentation is white. +HTML_COLORSTYLE = LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -- cgit v1.2.3 From 337866bea1538ac2b7725265856f53a63fabec48 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Fri, 16 Sep 2022 09:57:39 +0200 Subject: Advise doxygen 1.9.5 as it is now available on conda --- src/common/doc/installation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/common/doc/installation.h b/src/common/doc/installation.h index 28526498..63a37a25 100644 --- a/src/common/doc/installation.h +++ b/src/common/doc/installation.h @@ -45,7 +45,7 @@ make \endverbatim * * \subsection documentationgeneration C++ documentation * To generate the C++ documentation, the doxygen program - * is required (version ≥ 1.9.3 is advised). Run the following command in a terminal: + * is required (version ≥ 1.9.5 is advised). Run the following command in a terminal: * \verbatim make doxygen \endverbatim * Documentation will be generated in a folder named html. * -- cgit v1.2.3 From e4073eb21d4edf3cc23e59af9bc45c70d77c23ed Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau Date: Wed, 5 Oct 2022 08:45:36 +0200 Subject: doc review: confusion between i.e. and e.g. --- .../include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h index e166c3ee..4c0c7dad 100644 --- a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h @@ -197,7 +197,7 @@ class Skeleton_blocker_sub_complex : public ComplexType { /** * @remark waste of time to create a new simplex each time when we could use instead of addresses_sigma_in_link a - * simplex with special values (ComplexDS::null_vertex i.e.) to indicate that a vertex does not belong to the complex. + * simplex with special values (ComplexDS::null_vertex e.g.) to indicate that a vertex does not belong to the complex. */ template bool proper_face_in_union( -- cgit v1.2.3