From 5ce1ee8976ced78de839ef629522c95324b2fabd Mon Sep 17 00:00:00 2001 From: yuichi-ike Date: Mon, 6 Apr 2020 16:25:27 +0900 Subject: weighted rips added --- src/python/CMakeLists.txt | 3 +++ src/python/gudhi/weighted_rips_complex.py | 41 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/python/gudhi/weighted_rips_complex.py diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index d7a6a4db..cac4553a 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -415,6 +415,9 @@ if(PYTHONINTERP_FOUND) add_gudhi_py_test(test_dtm) endif() + # Weighted Rips + add_gudhi_py_test(test_weighted_rips) + # Documentation generation is available through sphinx - requires all modules if(SPHINX_PATH) if(MATPLOTLIB_FOUND) diff --git a/src/python/gudhi/weighted_rips_complex.py b/src/python/gudhi/weighted_rips_complex.py new file mode 100644 index 00000000..34a627cb --- /dev/null +++ b/src/python/gudhi/weighted_rips_complex.py @@ -0,0 +1,41 @@ +# 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): Raphaël Tinarrage and Yuichi Ike +# +# Copyright (C) 2020 Inria, Copyright (C) 2020 FUjitsu Laboratories Ltd. +# +# Modification(s): +# - YYYY/MM Author: Description of the modification + +from gudhi import SimplexTree + +class WeightedRipsComplex: + """ + class to generate a weighted Rips complex + from a distance matrix and filtration value + """ + def __init__(self, + distance_matrix=None, + filtration_values=None, + max_filtration=float('inf'), sparse=None): + self.distance_matrix = distance_matrix + self.filtration_values = filtration_values + self.max_filtration = max_filtration + + def create_simplex_tree(self, max_dimension): + dist = self.distance_matrix + F = self.filtration_values + num_pts = len(dist) + + st = SimplexTree() + + for i in range(num_pts): + if F[i] < self.max_filtration: + st.insert([i], F[i]) + for i in range(num_pts): + for j in range(num_pts): + value = (dist[i][j] + F[i] + F[j]) / 2 + if value < self.max_filtration: + st.insert([i,j], filtration=value) + return st + -- cgit v1.2.3 From fadeb80b46001779e2a998941a02195921b03124 Mon Sep 17 00:00:00 2001 From: yuichi-ike Date: Mon, 6 Apr 2020 16:31:59 +0900 Subject: test_weighted_rips added --- src/python/test/test_weighted_rips.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/python/test/test_weighted_rips.py diff --git a/src/python/test/test_weighted_rips.py b/src/python/test/test_weighted_rips.py new file mode 100644 index 00000000..f0db6798 --- /dev/null +++ b/src/python/test/test_weighted_rips.py @@ -0,0 +1,27 @@ +""" 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): Yuichi Ike + + Copyright (C) 2020 Inria + + Modification(s): + - YYYY/MM Author: Description of the modification +""" + +from gudhi.weighted_rips_complex import WeightedRipsComplex +from gudhi.point_cloud.dtm import DTM +import numpy +from scipy.spatial.distance import cdist +import pytest + +def test_dtm_rips_complex(): + pts = numpy.array([[2.0, 2], [0, 1], [3, 4]]) + dist = cdist(pts,pts) + dtm = DTM(2, q=2, metric="precomputed") + r = dtm.fit_transform(dist) + w_rips = WeightedRipsComplex(distance_mattix=dist, filtration_values=r) + st = w_rips.create_simplex_tree(max_dimension=2) + diag = st.persistence() + assert diag == [(0, (1.5811388300841898, float("inf"))), (0, (1.5811388300841898, 2.699172818834085)), (0, (1.5811388300841898, 2.699172818834085))] + + \ No newline at end of file -- cgit v1.2.3 From 5737c5e1e89cc4c939a784742f25b26ca163332d Mon Sep 17 00:00:00 2001 From: yuichi-ike Date: Mon, 6 Apr 2020 16:43:55 +0900 Subject: comments added --- src/python/gudhi/weighted_rips_complex.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/python/gudhi/weighted_rips_complex.py b/src/python/gudhi/weighted_rips_complex.py index 34a627cb..84e8e38e 100644 --- a/src/python/gudhi/weighted_rips_complex.py +++ b/src/python/gudhi/weighted_rips_complex.py @@ -17,12 +17,26 @@ class WeightedRipsComplex: def __init__(self, distance_matrix=None, filtration_values=None, - max_filtration=float('inf'), sparse=None): + max_filtration=float('inf')): + """ + Parameters: + distance_matrix: list of list of float, + distance matrix (full square or lower triangular) + filtration_values: list of float, + flitration value for each index + max_filtration: float, + specifies the maximal filtration value to be considered + """ self.distance_matrix = distance_matrix self.filtration_values = filtration_values self.max_filtration = max_filtration def create_simplex_tree(self, max_dimension): + """ + Parameter: + max_dimension: int + graph expansion until this given dimension + """ dist = self.distance_matrix F = self.filtration_values num_pts = len(dist) -- cgit v1.2.3 From 15586d479be885319dde6f703c3126176b796732 Mon Sep 17 00:00:00 2001 From: yuichi-ike Date: Mon, 6 Apr 2020 16:48:21 +0900 Subject: bug fixed --- src/python/gudhi/weighted_rips_complex.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/python/gudhi/weighted_rips_complex.py b/src/python/gudhi/weighted_rips_complex.py index 84e8e38e..7d14ac65 100644 --- a/src/python/gudhi/weighted_rips_complex.py +++ b/src/python/gudhi/weighted_rips_complex.py @@ -51,5 +51,7 @@ class WeightedRipsComplex: value = (dist[i][j] + F[i] + F[j]) / 2 if value < self.max_filtration: st.insert([i,j], filtration=value) + + st.expansion(max_dimension) return st -- cgit v1.2.3 From a4fa5f673784a842e9fac13003c843d454c888a4 Mon Sep 17 00:00:00 2001 From: yuichi-ike Date: Mon, 6 Apr 2020 21:19:55 +0900 Subject: bug fixed, parameter name changed --- src/python/CMakeLists.txt | 2 ++ src/python/gudhi/weighted_rips_complex.py | 19 +++++++++++-------- src/python/test/test_weighted_rips.py | 13 ++++++------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index cac4553a..4b87ed9b 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -57,6 +57,7 @@ if(PYTHONINTERP_FOUND) set(GUDHI_PYTHON_MODULES_EXTRA "${GUDHI_PYTHON_MODULES_EXTRA}'representations', ") set(GUDHI_PYTHON_MODULES_EXTRA "${GUDHI_PYTHON_MODULES_EXTRA}'wasserstein', ") set(GUDHI_PYTHON_MODULES_EXTRA "${GUDHI_PYTHON_MODULES_EXTRA}'point_cloud', ") + set(GUDHI_PYTHON_MODULES_EXTRA "${GUDHI_PYTHON_MODULES_EXTRA}'weighted_rips_complex', ") add_gudhi_debug_info("Python version ${PYTHON_VERSION_STRING}") add_gudhi_debug_info("Cython version ${CYTHON_VERSION}") @@ -228,6 +229,7 @@ if(PYTHONINTERP_FOUND) file(COPY "gudhi/representations" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi/") file(COPY "gudhi/wasserstein.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") file(COPY "gudhi/point_cloud" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") + file(COPY "gudhi/weighted_rips_complex.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/gudhi") add_custom_command( OUTPUT gudhi.so diff --git a/src/python/gudhi/weighted_rips_complex.py b/src/python/gudhi/weighted_rips_complex.py index 7d14ac65..9df2ddf9 100644 --- a/src/python/gudhi/weighted_rips_complex.py +++ b/src/python/gudhi/weighted_rips_complex.py @@ -1,6 +1,6 @@ # This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. # See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. -# Author(s): Raphaël Tinarrage and Yuichi Ike +# Author(s): Raphaël Tinarrage, Yuichi Ike, Masatoshi Takenouchi # # Copyright (C) 2020 Inria, Copyright (C) 2020 FUjitsu Laboratories Ltd. # @@ -12,23 +12,26 @@ from gudhi import SimplexTree class WeightedRipsComplex: """ class to generate a weighted Rips complex - from a distance matrix and filtration value + from a distance matrix and weights on vertices """ def __init__(self, - distance_matrix=None, - filtration_values=None, + distance_matrix, + weights=None, max_filtration=float('inf')): """ Parameters: distance_matrix: list of list of float, distance matrix (full square or lower triangular) filtration_values: list of float, - flitration value for each index + weight for each vertex max_filtration: float, specifies the maximal filtration value to be considered """ self.distance_matrix = distance_matrix - self.filtration_values = filtration_values + if weights is not None: + self.weights = weights + else: + self.weights = [0] * len(distance_matrix) self.max_filtration = max_filtration def create_simplex_tree(self, max_dimension): @@ -38,7 +41,7 @@ class WeightedRipsComplex: graph expansion until this given dimension """ dist = self.distance_matrix - F = self.filtration_values + F = self.weights num_pts = len(dist) st = SimplexTree() @@ -47,7 +50,7 @@ class WeightedRipsComplex: if F[i] < self.max_filtration: st.insert([i], F[i]) for i in range(num_pts): - for j in range(num_pts): + for j in range(i): value = (dist[i][j] + F[i] + F[j]) / 2 if value < self.max_filtration: st.insert([i,j], filtration=value) diff --git a/src/python/test/test_weighted_rips.py b/src/python/test/test_weighted_rips.py index f0db6798..7896fb78 100644 --- a/src/python/test/test_weighted_rips.py +++ b/src/python/test/test_weighted_rips.py @@ -1,6 +1,6 @@ """ This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - Author(s): Yuichi Ike + Author(s): Yuichi Ike and Masatoshi Takenouchi Copyright (C) 2020 Inria @@ -10,18 +10,17 @@ from gudhi.weighted_rips_complex import WeightedRipsComplex from gudhi.point_cloud.dtm import DTM -import numpy +import numpy as np from scipy.spatial.distance import cdist import pytest def test_dtm_rips_complex(): - pts = numpy.array([[2.0, 2], [0, 1], [3, 4]]) + pts = np.array([[2.0, 2], [0, 1], [3, 4]]) dist = cdist(pts,pts) dtm = DTM(2, q=2, metric="precomputed") r = dtm.fit_transform(dist) - w_rips = WeightedRipsComplex(distance_mattix=dist, filtration_values=r) + w_rips = WeightedRipsComplex(distance_mattix=dist, weights=r) st = w_rips.create_simplex_tree(max_dimension=2) - diag = st.persistence() - assert diag == [(0, (1.5811388300841898, float("inf"))), (0, (1.5811388300841898, 2.699172818834085)), (0, (1.5811388300841898, 2.699172818834085))] + persistence_intervals0 = st.persistence_intervals_in_dimension(0) + assert persistence_intervals0 == pytest.approx(np.array([[1.58113883, 2.69917282],[1.58113883, 2.69917282], [1.58113883, float("inf")]])) - \ No newline at end of file -- cgit v1.2.3 From 4294e5fc6e1bff246a7d22f1bd98f91b62f14163 Mon Sep 17 00:00:00 2001 From: yuichi-ike Date: Tue, 7 Apr 2020 09:36:03 +0900 Subject: filtration value fixed --- src/python/gudhi/weighted_rips_complex.py | 2 +- src/python/test/test_weighted_rips.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/python/gudhi/weighted_rips_complex.py b/src/python/gudhi/weighted_rips_complex.py index 9df2ddf9..7e504b2c 100644 --- a/src/python/gudhi/weighted_rips_complex.py +++ b/src/python/gudhi/weighted_rips_complex.py @@ -51,7 +51,7 @@ class WeightedRipsComplex: st.insert([i], F[i]) for i in range(num_pts): for j in range(i): - value = (dist[i][j] + F[i] + F[j]) / 2 + value = max(F[i], F[j], (dist[i][j] + F[i] + F[j]) / 2) if value < self.max_filtration: st.insert([i,j], filtration=value) diff --git a/src/python/test/test_weighted_rips.py b/src/python/test/test_weighted_rips.py index 7896fb78..a3235276 100644 --- a/src/python/test/test_weighted_rips.py +++ b/src/python/test/test_weighted_rips.py @@ -14,13 +14,23 @@ import numpy as np from scipy.spatial.distance import cdist import pytest +def test_non_dtm_rips_complex(): + dist = [[], [1]] + weights = [1, 100] + w_rips = WeightedRipsComplex(distance_matrix=dist, weights=weights) + st = w_rips.create_simplex_tree(max_dimension=2) + assert st.filtration([0,1]) == pytest.approx(100.0) + + def test_dtm_rips_complex(): pts = np.array([[2.0, 2], [0, 1], [3, 4]]) dist = cdist(pts,pts) dtm = DTM(2, q=2, metric="precomputed") r = dtm.fit_transform(dist) - w_rips = WeightedRipsComplex(distance_mattix=dist, weights=r) + w_rips = WeightedRipsComplex(distance_matrix=dist, weights=r) st = w_rips.create_simplex_tree(max_dimension=2) + st.persistence() persistence_intervals0 = st.persistence_intervals_in_dimension(0) assert persistence_intervals0 == pytest.approx(np.array([[1.58113883, 2.69917282],[1.58113883, 2.69917282], [1.58113883, float("inf")]])) + -- cgit v1.2.3