Skip to content

Commit

Permalink
Extend UST class to handle weighted graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
BereniceCourant committed Jan 5, 2020
1 parent 3df7987 commit b7ccd08
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 16 deletions.
13 changes: 6 additions & 7 deletions dppy/exotic_dpps.py
Expand Up @@ -487,9 +487,9 @@ def __init__(self, graph):
self.edge_labels = {edge: r'$e_{}$'.format(i)
for i, edge in enumerate(self.edges)}

self.neighbors = [list(graph.neighbors(v))
for v in range(self.nb_nodes)]

#self.neighbors = [list(graph.neighbors(v)) for v in range(self.nb_nodes)]
self.adjacency_matrix = nx.adjacency_matrix(self.graph)
self.sampling_mode = 'Wilson' # Default (avoid eig_vecs computation)
self._sampling_modes = {'markov-chain': ['Wilson', 'Aldous-Broder', 'Wilson_node'],
'spectral-method': ['GS'],
Expand Down Expand Up @@ -559,16 +559,15 @@ def sample(self, mode='Wilson', root=None, random_state=None):

if self.sampling_mode in self._sampling_modes['markov-chain']:
if self.sampling_mode == 'Wilson':
sampl = ust_sampler_wilson(self.neighbors,
sampl = ust_sampler_wilson(self.adjacency_matrix,
random_state=rng)

elif self.sampling_mode == 'Aldous-Broder':
sampl = ust_sampler_aldous_broder(self.neighbors,
sampl = ust_sampler_aldous_broder(self.adjacency_matrix,
random_state=rng)

elif self.sampling_mode == 'Wilson_node':
W = nx.adjacency_matrix(self.graph).todense()
Y, P, sampl = ust_sampler_wilson_nodes(W, absorbing_weight=1, random_state=rng)
Y, P, sampl = ust_sampler_wilson_nodes(self.adjacency_matrix, absorbing_weight=1, random_state=rng)

This comment has been minimized.

Copy link
@guilgautier

guilgautier Jan 7, 2020

Owner

More explicit name of variable are expected



elif self.sampling_mode in self._sampling_modes['spectral-method']:
Expand Down
33 changes: 24 additions & 9 deletions dppy/exotic_dpps_core.py
Expand Up @@ -36,14 +36,22 @@
from dppy.utils import check_random_state


def ust_sampler_wilson(list_of_neighbors, root=None,
def ust_sampler_wilson(W, root=None,

This comment has been minimized.

Copy link
@guilgautier

guilgautier Jan 7, 2020

Owner

More explicit name why not a simple adjacency_matrix?

random_state=None):

"""
Compute a random spanning tree of a graph G given by his adjacency matrix
param W:
Adjacency matrix of the Graph
param W:

This comment has been minimized.

Copy link
@guilgautier

guilgautier Jan 7, 2020

Owner

type note param

scipy.sparse.csr_matrix
"""
rng = check_random_state(random_state)

# Initialize the tree
wilson_tree_graph = nx.Graph()
nb_nodes = len(list_of_neighbors)
#nb_nodes = len(list_of_neighbors)
nb_nodes = W.shape[0]

# Initialize the root, if root not specified start from any node
n0 = root if root else rng.choice(nb_nodes) # size=1)[0]
Expand All @@ -57,7 +65,10 @@ def ust_sampler_wilson(list_of_neighbors, root=None,
while nb_nodes_in_tree < nb_nodes: # |Tree| = |V| - 1

# visit a neighbor of n0 uniformly at random
n1 = rng.choice(list_of_neighbors[n0]) # size=1)[0]
#n1 = rng.choice(list_of_neighbors[n0]) # size=1)[0]
weights = (W.getrow(n0).toarray())[0].astype('float')
weights /= np.sum(weights)

This comment has been minimized.

Copy link
@guilgautier

guilgautier Jan 7, 2020

Owner

Why rescaling the weights on the fly instead of rescaling the adjacency matrix before the while loop?

What if an entire line of transition_probabilities is equal to zero? This would create a division by zero.
1072e4c#r36665637

n1 = rng.choice(np.arange(nb_nodes), p=weights)

This comment has been minimized.

Copy link
@guilgautier

guilgautier Jan 7, 2020

Owner

Is np.arange(nb_nodes) more efficient than nb_nodes?


if state[n1] == -1: # not visited => continue the walk

Expand Down Expand Up @@ -105,7 +116,7 @@ def ust_sampler_wilson_nodes(W, absorbing_weight=0, random_state=None):
:param W:
Adjacency matrix of the graph
:type W:
array_like
scipy.sparse.csr_matrix
:param absorbing_weight:
Weight of the node Delta added to the graph
Expand Down Expand Up @@ -138,7 +149,7 @@ def ust_sampler_wilson_nodes(W, absorbing_weight=0, random_state=None):
all_path = []

# Compute the probabilities of transition
transition_probabilities = np.pad(W, [(0, 0), (0, 1)], mode='constant', constant_values=absorbing_weight).astype('float')
transition_probabilities = np.pad(W.toarray(), [(0, 0), (0, 1)], mode='constant', constant_values=absorbing_weight).astype('float')
norm = np.sum(transition_probabilities, axis=1)
transition_probabilities[np.nonzero(norm), :] /= norm[np.nonzero(norm), None]

Expand Down Expand Up @@ -211,14 +222,15 @@ def ust_sampler_wilson_nodes(W, absorbing_weight=0, random_state=None):
#print("Nu=", Nu)
return Y, all_path, wilson_tree_from_path

def ust_sampler_aldous_broder(list_of_neighbors, root=None,
def ust_sampler_aldous_broder(W, root=None,
random_state=None):

rng = check_random_state(random_state)

# Initialize the tree
aldous_tree_graph = nx.Graph()
nb_nodes = len(list_of_neighbors)
#nb_nodes = len(list_of_neighbors)
nb_nodes = W.shape[0]

# Initialize the root, if root not specified start from any node
n0 = root if root else rng.choice(nb_nodes) # size=1)[0]
Expand All @@ -231,7 +243,10 @@ def ust_sampler_aldous_broder(list_of_neighbors, root=None,
while nb_nodes_in_tree < nb_nodes:

# visit a neighbor of n0 uniformly at random
n1 = rng.choice(list_of_neighbors[n0]) # size=1)[0]
#n1 = rng.choice(list_of_neighbors[n0]) # size=1)[0]
weights = (W.getrow(n0).toarray())[0].astype('float')
weights /= np.sum(weights)
n1 = rng.choice(np.arange(nb_nodes), p=weights)

if visited[n1]:
pass # continue the walk
Expand Down

0 comments on commit b7ccd08

Please sign in to comment.