summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/python/gudhi/tensorflow/cubical_layer.py20
-rw-r--r--src/python/gudhi/tensorflow/lower_star_simplex_tree_layer.py21
-rw-r--r--src/python/gudhi/tensorflow/rips_layer.py19
3 files changed, 41 insertions, 19 deletions
diff --git a/src/python/gudhi/tensorflow/cubical_layer.py b/src/python/gudhi/tensorflow/cubical_layer.py
index 8fe9cff0..b16c512f 100644
--- a/src/python/gudhi/tensorflow/cubical_layer.py
+++ b/src/python/gudhi/tensorflow/cubical_layer.py
@@ -8,7 +8,7 @@ from ..cubical_complex import CubicalComplex
# The parameters of the model are the pixel values.
-def _Cubical(Xflat, Xdim, dimensions, min_persistence):
+def _Cubical(Xflat, Xdim, dimensions):
# Parameters: Xflat (flattened image),
# Xdim (shape of non-flattened image)
# dimensions (homology dimensions)
@@ -16,7 +16,7 @@ def _Cubical(Xflat, Xdim, dimensions, min_persistence):
# Compute the persistence pairs with Gudhi
# We reverse the dimensions because CubicalComplex uses Fortran ordering
cc = CubicalComplex(dimensions=Xdim[::-1], top_dimensional_cells=Xflat)
- cc.compute_persistence(min_persistence=min_persistence)
+ cc.compute_persistence()
# Retrieve and ouput image indices/pixels corresponding to positive and negative simplices
cof_pp = cc.cofaces_of_persistence_pairs()
@@ -37,17 +37,19 @@ class CubicalLayer(tf.keras.layers.Layer):
"""
TensorFlow layer for computing cubical persistence out of a cubical complex
"""
- def __init__(self, dimensions, min_persistence=0., **kwargs):
+ def __init__(self, dimensions, min_persistence=None, **kwargs):
"""
Constructor for the CubicalLayer class
Parameters:
dimensions (List[int]): homology dimensions
+ min_persistence (List[float]): minimum distance-to-diagonal of the points in the output persistence diagrams (default None, in which case 0. is used for all dimensions)
"""
super().__init__(dynamic=True, **kwargs)
self.dimensions = dimensions
- self.min_persistence = min_persistence
-
+ self.min_persistence = min_persistence if min_persistence != None else [0. for _ in range(len(self.dimensions))]
+ assert len(self.min_persistence) == len(self.dimensions)
+
def call(self, X):
"""
Compute persistence diagram associated to a cubical complex filtered by some pixel values
@@ -62,7 +64,13 @@ class CubicalLayer(tf.keras.layers.Layer):
# Don't compute gradient for this operation
Xflat = tf.reshape(X, [-1])
Xdim = X.shape
- indices = _Cubical(Xflat.numpy(), Xdim, self.dimensions, self.min_persistence)
+ indices = _Cubical(Xflat.numpy(), Xdim, self.dimensions)
# Get persistence diagram by simply picking the corresponding entries in the image
self.dgms = [tf.reshape(tf.gather(Xflat, indice), [-1,2]) for indice in indices]
+ for idx_dim in range(len(self.min_persistence)):
+ min_pers = self.min_persistence[idx_dim]
+ if min_pers >= 0:
+ finite_dgm = self.dgms[idx_dim]
+ persistent_indices = np.argwhere(np.abs(finite_dgm[:,1]-finite_dgm[:,0]) > min_pers).ravel()
+ self.dgms[idx_dim] = tf.gather(finite_dgm, indices=persistent_indices)
return self.dgms
diff --git a/src/python/gudhi/tensorflow/lower_star_simplex_tree_layer.py b/src/python/gudhi/tensorflow/lower_star_simplex_tree_layer.py
index 5902e4a1..e1627944 100644
--- a/src/python/gudhi/tensorflow/lower_star_simplex_tree_layer.py
+++ b/src/python/gudhi/tensorflow/lower_star_simplex_tree_layer.py
@@ -7,7 +7,7 @@ import tensorflow as tf
# The parameters of the model are the vertex function values of the simplex tree.
-def _LowerStarSimplexTree(simplextree, filtration, dimensions, min_persistence):
+def _LowerStarSimplexTree(simplextree, filtration, dimensions):
# Parameters: simplextree (simplex tree on which to compute persistence)
# filtration (function values on the vertices of st),
# dimensions (homology dimensions),
@@ -21,7 +21,7 @@ def _LowerStarSimplexTree(simplextree, filtration, dimensions, min_persistence):
simplextree.make_filtration_non_decreasing()
# Compute persistence diagram
- simplextree.compute_persistence(min_persistence=min_persistence)
+ simplextree.compute_persistence()
# Get vertex pairs for optimization. First, get all simplex pairs
pairs = simplextree.lower_star_persistence_generators()
@@ -43,19 +43,21 @@ class LowerStarSimplexTreeLayer(tf.keras.layers.Layer):
"""
TensorFlow layer for computing lower-star persistence out of a simplex tree
"""
- def __init__(self, simplextree, dimensions, min_persistence=0., **kwargs):
+ def __init__(self, simplextree, dimensions, min_persistence=None, **kwargs):
"""
Constructor for the LowerStarSimplexTreeLayer class
Parameters:
simplextree (gudhi.SimplexTree): underlying simplex tree. Its vertices MUST be named with integers from 0 to n = number of vertices
dimensions (List[int]): homology dimensions
+ min_persistence (List[float]): minimum distance-to-diagonal of the points in the output persistence diagrams (default None, in which case 0. is used for all dimensions)
"""
super().__init__(dynamic=True, **kwargs)
self.dimensions = dimensions
self.simplextree = simplextree
- self.min_persistence = min_persistence
-
+ self.min_persistence = min_persistence if min_persistence != None else [0. for _ in range(len(self.dimensions))]
+ assert len(self.min_persistence) == len(self.dimensions)
+
def call(self, filtration):
"""
Compute lower-star persistence diagram associated to a function defined on the vertices of the simplex tree
@@ -67,12 +69,17 @@ class LowerStarSimplexTreeLayer(tf.keras.layers.Layer):
dgms (list of tuple of TensorFlow variables): list of lower-star persistence diagrams of length self.dimensions, where each element of the list is a tuple that contains the finite and essential persistence diagrams of shapes [num_finite_points, 2] and [num_essential_points, 1] respectively
"""
# Don't try to compute gradients for the vertex pairs
- indices = _LowerStarSimplexTree(self.simplextree, filtration.numpy(), self.dimensions, self.min_persistence)
+ indices = _LowerStarSimplexTree(self.simplextree, filtration.numpy(), self.dimensions)
# Get persistence diagrams
self.dgms = []
for idx_dim, dimension in enumerate(self.dimensions):
finite_dgm = tf.reshape(tf.gather(filtration, indices[idx_dim][0]), [-1,2])
essential_dgm = tf.reshape(tf.gather(filtration, indices[idx_dim][1]), [-1,1])
- self.dgms.append((finite_dgm, essential_dgm))
+ min_pers = self.min_persistence[idx_dim]
+ if min_pers >= 0:
+ persistent_indices = np.argwhere(np.abs(finite_dgm[:,1]-finite_dgm[:,0]) > min_pers).ravel()
+ self.dgms.append((tf.gather(finite_dgm, indices=persistent_indices), essential_dgm))
+ else:
+ self.dgms.append((finite_dgm, essential_dgm))
return self.dgms
diff --git a/src/python/gudhi/tensorflow/rips_layer.py b/src/python/gudhi/tensorflow/rips_layer.py
index 97f28d74..a5f212e3 100644
--- a/src/python/gudhi/tensorflow/rips_layer.py
+++ b/src/python/gudhi/tensorflow/rips_layer.py
@@ -8,7 +8,7 @@ from ..rips_complex import RipsComplex
# The parameters of the model are the point coordinates.
-def _Rips(DX, max_edge, dimensions, min_persistence):
+def _Rips(DX, max_edge, dimensions):
# Parameters: DX (distance matrix),
# max_edge (maximum edge length for Rips filtration),
# dimensions (homology dimensions)
@@ -16,7 +16,7 @@ def _Rips(DX, max_edge, dimensions, min_persistence):
# Compute the persistence pairs with Gudhi
rc = RipsComplex(distance_matrix=DX, max_edge_length=max_edge)
st = rc.create_simplex_tree(max_dimension=max(dimensions)+1)
- st.compute_persistence(min_persistence=min_persistence)
+ st.compute_persistence()
pairs = st.flag_persistence_generators()
L_indices = []
@@ -40,18 +40,20 @@ class RipsLayer(tf.keras.layers.Layer):
"""
TensorFlow layer for computing Rips persistence out of a point cloud
"""
- def __init__(self, dimensions, maximum_edge_length=12, min_persistence=0., **kwargs):
+ def __init__(self, dimensions, maximum_edge_length=12, min_persistence=None, **kwargs):
"""
Constructor for the RipsLayer class
Parameters:
maximum_edge_length (float): maximum edge length for the Rips complex
dimensions (List[int]): homology dimensions
+ min_persistence (List[float]): minimum distance-to-diagonal of the points in the output persistence diagrams (default None, in which case 0. is used for all dimensions)
"""
super().__init__(dynamic=True, **kwargs)
self.max_edge = maximum_edge_length
self.dimensions = dimensions
- self.min_persistence = min_persistence
+ self.min_persistence = min_persistence if min_persistence != None else [0. for _ in range(len(self.dimensions))]
+ assert len(self.min_persistence) == len(self.dimensions)
def call(self, X):
"""
@@ -67,7 +69,7 @@ class RipsLayer(tf.keras.layers.Layer):
DX = tf.math.sqrt(tf.reduce_sum((tf.expand_dims(X, 1)-tf.expand_dims(X, 0))**2, 2))
# Compute vertices associated to positive and negative simplices
# Don't compute gradient for this operation
- indices = _Rips(DX.numpy(), self.max_edge, self.dimensions, self.min_persistence)
+ indices = _Rips(DX.numpy(), self.max_edge, self.dimensions)
# Get persistence diagrams by simply picking the corresponding entries in the distance matrix
self.dgms = []
for idx_dim, dimension in enumerate(self.dimensions):
@@ -79,6 +81,11 @@ class RipsLayer(tf.keras.layers.Layer):
reshaped_cur_idx = tf.reshape(cur_idx[0], [-1,3])
finite_dgm = tf.concat([tf.zeros([reshaped_cur_idx.shape[0],1]), tf.reshape(tf.gather_nd(DX, reshaped_cur_idx[:,1:]), [-1,1])], axis=1)
essential_dgm = tf.zeros([cur_idx[1].shape[0],1])
- self.dgms.append((finite_dgm, essential_dgm))
+ min_pers = self.min_persistence[idx_dim]
+ if min_pers >= 0:
+ persistent_indices = np.argwhere(np.abs(finite_dgm[:,1]-finite_dgm[:,0]) > min_pers).ravel()
+ self.dgms.append((tf.gather(finite_dgm, indices=persistent_indices), essential_dgm))
+ else:
+ self.dgms.append((finite_dgm, essential_dgm))
return self.dgms