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])