1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
import numpy as np
import tensorflow as tf
from ..cubical_complex import CubicalComplex
######################
# Cubical filtration #
######################
# The parameters of the model are the pixel values.
def _Cubical(X, dimensions):
# Parameters: X (image),
# dimensions (homology dimensions)
# Compute the persistence pairs with Gudhi
Xs = X.shape
cc = CubicalComplex(top_dimensional_cells=X)
cc.compute_persistence()
# Retrieve and ouput image indices/pixels corresponding to positive and negative simplices
cof_pp = cc.cofaces_of_persistence_pairs()
L_cofs = []
for dim in dimensions:
try:
cof = cof_pp[0][dim]
except IndexError:
cof = np.array([])
L_cofs.append(np.array(cof, dtype=np.int32))
return L_cofs
class CubicalLayer(tf.keras.layers.Layer):
"""
TensorFlow layer for computing cubical persistence out of a cubical complex
"""
def __init__(self, dimensions, **kwargs):
"""
Constructor for the CubicalLayer class
Parameters:
dimensions (list of int): homology dimensions
"""
super().__init__(dynamic=True, **kwargs)
self.dimensions = dimensions
def build(self):
super.build()
def call(self, X):
"""
Compute persistence diagram associated to a cubical complex filtered by some pixel values
Parameters:
X (TensorFlow variable): pixel values of the cubical complex
Returns:
dgms (list of TensorFlow variables): list of cubical persistence diagrams of length self.dimensions, where each element contains a finite persistence diagram of shape [num_finite_points, 2]
"""
# Compute pixels associated to positive and negative simplices
# Don't compute gradient for this operation
indices = _Cubical(X.numpy(), self.dimensions)
# Get persistence diagram by simply picking the corresponding entries in the image
self.dgms = [tf.reshape(tf.gather( tf.reshape(tf.transpose(X), [-1]), indice ), [-1,2]) for indice in indices]
return self.dgms
|