def clustering(self, G, verbose=False, max_iter=1000000, leaders=None): # init nodes = list(G.nodes) if not leaders: leaders = {node: NONE for node in nodes} else: for truck in G.nodes: if truck not in leaders or (leaders[truck] >= 0 and leaders[truck] not in G[truck]): leaders[truck] = NONE # caution: the list use negative gains for since it is a min heap # and we want to change the node with biggest gain gains = {n: [-get_delta_u(n, leaders, G), n] for n in nodes} gain_heap = [] for key in gains: # add all nodes with positive gain to the heap if gains[key][0] < 0.: heapq.heappush(gain_heap, gains[key]) # loop counter = 0 while counter < max_iter: counter += 1 # iteration count # select a node and calculate its delta_u node = self.select_node(nodes, gains, gain_heap) if node == -1: break # update the role of the node if leaders[node] == LEADER: # become a follower change_to_follower(node, leaders, G, verbose) else: # become a leader change_to_leader(node, leaders, G, verbose) # update the gains self.update_u(node, leaders, gains, gain_heap, G) if counter == max_iter: print "Max" # clean-up # check if all leaders have followers for n in G.nodes: if leaders[n] == LEADER: has_followers = False for pot_follower in G.inverted_nodes[n]: if leaders[pot_follower] == n: has_followers = True break if not has_followers: leaders[n] = NONE # convert to sets N_l = set([nodel for nodel in nodes if leaders[nodel] == LEADER]) N_f = set([nodel for nodel in nodes if leaders[nodel] != LEADER]) return N_f, N_l, leaders, counter
def update_u(self, n, leaders, gains, gain_heap, G): # updates gains according to leader for all two-hop of # neighbors of n # it would be possible to integrate this with change_to_leader/change_to_follower # for improved performance # calculate and iterate of two hop neighbors neighbors = get_two_hop_neighbors(n, G) for nb in neighbors: gain = get_delta_u(nb, leaders, G) gains[nb] = [-gain, nb] # new entry
def clustering(self, G, debug=False, leaders=None): X = {node: NONE for node in G.nodes} # no leaders Y = {node: LEADER for node in G.nodes} # all leaders nodes = list(G.nodes) if debug: nodes.sort() for i, x in enumerate(nodes): a = get_delta_u(x, X, G) b = get_delta_u(x, Y, G) if self.deterministic: keep_i = a >= b else: ap = max(a, 0.) bp = max(b, 0.) # this reinitializes the random generation at each call always giving the same random number # make this a class attribute keep_i = not ((ap == 0 and bp == 0) or ap / (ap + bp) < self.local_random.random()) if keep_i: change_to_leader(x, X, G, False) else: # become a leader change_to_follower(x, Y, G, False) # check if all leaders have followers for n in G.nodes: if X[n] == LEADER: has_followers = False for pot_follower in G.inverted_nodes[n]: if X[pot_follower] == n: has_followers = True break if not has_followers: X[n] = NONE N_l = set([nodel for nodel in nodes if X[nodel] == LEADER]) N_f = set([nodel for nodel in nodes if X[nodel] != LEADER]) return N_f, N_l, X, len(nodes)
def update_u(self, n, leaders, gains, gain_heap, G): # updates gains and gain_heap according to leader for all two-hop of # neighbors of n # it would be possible to integrate this with change_to_leader/change_to_follower # for improved performance # calculate and iterate of two hop neighbors neighbors = get_two_hop_neighbors(n, G) for nb in neighbors: gain = get_delta_u(nb, leaders, G) # update heap if gains[nb][0] != -gain: # gain changed gains[nb][1] = -1 # old entry is invalid gains[nb] = [-gain, nb] # new entry if gain > 0.: # push on the heap if the gain is positive heapq.heappush(gain_heap, gains[nb])