Skip to content

Commit 40e3dbf

Browse files
authored
Merge pull request #7 from gdasoulas/wrapup-first-submission
Wrapup first submission
2 parents 8cd6e40 + 1828b0b commit 40e3dbf

File tree

2 files changed

+115
-71
lines changed

2 files changed

+115
-71
lines changed

modules/transforms/liftings/graph2simplicial/latentclique_lifting.py

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,14 @@ def lift_topology(
6868
dict
6969
The lifted topology.
7070
"""
71-
G = self._generate_graph_from_data(data)
72-
adj = nx.adjacency_matrix(G).toarray()
73-
71+
# Make adjacency matrix from data
72+
N = data.num_nodes
73+
adj = np.zeros((N, N))
74+
for i, j in data.edge_index.T:
75+
adj[i, j] = 1
76+
adj[j, i] = 1
77+
78+
# Create the latent clique model and fit using Gibbs sampling
7479
mod = _LatentCliqueModel(
7580
adj,
7681
init=self.init,
@@ -80,11 +85,11 @@ def lift_topology(
8085
it = self.it if self.it is not None else data.num_edges
8186
mod.sample(sample_hypers=True, num_iters=it, do_gibbs=True, verbose=verbose)
8287

83-
adj = mod.Z.T @ mod.Z
84-
adj = np.minimum(adj - np.diag(np.diag(adj)), 1)
85-
g = nx.from_numpy_matrix(adj)
86-
edges = torch.LongTensor(list(g.edges()), device=data.edge_index.device).T
87-
edges = torch.cat([edges, edges.flip(0)], dim=1)
88+
# Translate fitted model to a new topology
89+
cic = mod.Z.T @ mod.Z
90+
adj = np.minimum(cic - np.diag(np.diag(cic)), 1)
91+
edges = np.array(np.where(adj)).T
92+
edges = torch.LongTensor(edges).to(data.edge_index.device)
8893
new_data = torch_geometric.data.Data(x=data.x, edge_index=edges)
8994
return SimplicialCliqueLifting().lift_topology(new_data)
9095

@@ -115,7 +120,7 @@ class _LatentCliqueModel:
115120
Adjacency matrix of the input graph.
116121
edge_prob_mean : float
117122
Mean of the prior distribution of pie ~ Beta
118-
where edge_prob_mean must be in (0, 1].
123+
where edge_prob_mean must be in (0, 1].
119124
When edge_prob_var is one, the value of edge_prob is fixed and not sampled.
120125
edge_prob_var : float
121126
Uncertainty of the prior distribution of pie ~ Beta(a, b)
@@ -147,7 +152,7 @@ class _LatentCliqueModel:
147152
Probability of an edge observation.
148153
lamb : float
149154
Rate parameter of the Poisson distribution for the number of cliques.
150-
It does not influence parameter learning. But is sampled for the
155+
It does not influence parameter learning. But is sampled for the
151156
likelihood computation.
152157
153158
**Note**: The values of (K, N) are used interchanged from the paper notation.
@@ -170,14 +175,26 @@ def __init__(
170175
# Initialize clique cover matrix
171176
self._init_Z()
172177

178+
# Initialize parameters
179+
self._init_params()
180+
181+
# Initialize hyperparameters
182+
self._init_hyperparams(edge_prob_mean, edge_prob_var)
183+
173184
# Current number of clusters
174185
self.K = self.Z.shape[0]
175186

176-
# Initialize parameters
187+
def _init_params(self):
188+
"""Initialize the parameters of the model."""
177189
self.alpha = 1.0
178190
self.sigma = 0.5
179191
self.c = 0.5
180-
self.edge_prob = edge_prob_mean
192+
self.edge_prob = 0.98
193+
194+
def _init_hyperparams(self, edge_prob_mean, edge_prob_var):
195+
# Validate the edge probability parameters
196+
assert 0 < edge_prob_mean <= 1
197+
assert edge_prob_var >= 0
181198

182199
# Parameter prior hyper-parameters
183200
# The priors of alpha, sigma, c and uninformative, so their are set to
@@ -376,26 +393,32 @@ def sample_hypers(self, step_size=0.1):
376393
a = self._edge_prob_params[0]
377394
b = self._edge_prob_params[1]
378395
# lp ratio comes from a beta distribution
379-
lp_ratio = (a - 1) * (
380-
np.log(edge_prob_prop) - np.log(self.edge_prob)
381-
) + (b - 1) * (np.log(1 - edge_prob_prop) - np.log(1 - self.edge_prob))
396+
lp_ratio = (a - 1) * (np.log(edge_prob_prop) - np.log(self.edge_prob)) + (
397+
b - 1
398+
) * (np.log(1 - edge_prob_prop) - np.log(1 - self.edge_prob))
382399
lratio = ll_new - ll_old + lp_ratio
383400
r = np.log(np.random.rand())
384401
if r < lratio:
385402
self.edge_prob = edge_prob_prop
386403

387404
c_prop = self.c + step_size * np.random.randn()
388-
if c_prop > -self.sigma:
389-
lp_ratio = (self._c_params[0] - 1) * (
390-
np.log(c_prop) - np.log(self.c)
391-
) + self._c_params[1] * (self.c - c_prop)
405+
if c_prop > -1 * self.sigma:
392406
ll_new = self.log_lik(c=c_prop)
407+
c_diff_new = c_prop + self.sigma
408+
lp_new = stats.gamma.logpdf(
409+
c_diff_new, self._c_params[0], scale=1 / self._c_params[1]
410+
)
411+
393412
ll_old = self.log_lik()
394-
lratio = ll_new - ll_old + lp_ratio
413+
c_diff_old = self.c + self.sigma
414+
lp_old = stats.gamma.logpdf(
415+
c_diff_old, self._c_params[0], scale=1 / self._c_params[1]
416+
)
417+
418+
lratio = ll_new - ll_old + lp_new - lp_old
395419
r = np.log(np.random.rand())
396420
if r < lratio:
397421
self.c = c_prop
398-
399422
# Sample c
400423
c_prop = self.c + step_size * np.random.randn()
401424

@@ -789,7 +812,7 @@ def _sample_from_ibp(K, alpha, sigma, c):
789812
adj = np.minimum(cic - np.diag(np.diag(cic)), 1)
790813

791814
# delete edges with prob 1 - exp(pi^)
792-
prob = np.exp(-(1 - pie)**2)
815+
prob = np.exp(-((1 - pie) ** 2))
793816
triu_mask = np.triu(np.ones_like(adj), 1)
794817
adj = np.random.binomial(1, prob, adj.shape) * adj * triu_mask
795818
adj = adj + adj.T

tutorials/graph2simplicial/latentclique_lifting.ipynb

Lines changed: 70 additions & 49 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)