diff options
author | MathieuCarriere <mathieu.carriere3@gmail.com> | 2021-12-04 13:22:23 +0100 |
---|---|---|
committer | MathieuCarriere <mathieu.carriere3@gmail.com> | 2021-12-04 13:22:23 +0100 |
commit | 96c7e5ce2f0146798f66c89421b0d23e98a2a390 (patch) | |
tree | f42bd81a37c98c0d7937363a7fed5a1411cadc82 /src/python/gudhi | |
parent | 979d12e00b4ea71391d132589ee3304e378459b9 (diff) |
update code and doc
Diffstat (limited to 'src/python/gudhi')
-rw-r--r-- | src/python/gudhi/tensorflow/cubical_layer.py | 20 | ||||
-rw-r--r-- | src/python/gudhi/tensorflow/lower_star_simplex_tree_layer.py | 21 | ||||
-rw-r--r-- | src/python/gudhi/tensorflow/rips_layer.py | 19 |
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 |