import networkx as nx
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import math
import random
import operator
################################################################################
# draw graph and color communities

def draw_comm_graph(G, comms):
	colors = [comms[v] for v in G.nodes()]
	
	nx.draw_kamada_kawai(G, with_labels=True, node_color=colors)
	plt.show()


################################################################################

G = nx.read_edgelist("karate.data", comments="%")
comms = {}
with open("karate.gt") as f:
	for line in f:
		(key, val) = line.split()
		comms[key] = int(val)

draw_comm_graph(G, comms)

################################################################################
# communities by clique decomposition

comms = {}
comm_count = 0
C = list(nx.clique.enumerate_all_cliques(G))
for c in reversed(list(C)):
	for v in c:
		if v not in dict.keys(comms):
			comms[v] = comm_count
	comm_count += 1

draw_comm_graph(G, comms)

################################################################################
# Agglomerative Procedures: the Ravasz Algorithm

comms = {}
for v in G.nodes():
	comms[v] = int(v)

g = G.copy()
while len(g.nodes()) > 1:
	S = {}
	for v in g.nodes():
		for u in g.nodes():
			if u == v: 
				continue
			a_uv = 0
			if g.has_edge(u,v):
				a_uv = 1
			s = len(list(nx.common_neighbors(g,u,v))) + a_uv
			s /= (min(g.degree(u),g.degree(v)) + 1 - a_uv)
			S[(u,v)] = s
	s = sorted(S.items(), key=operator.itemgetter(1), reverse=True)[0]
	if s[1] == 0:
		break
	
	e = s[0]
	g = nx.contracted_nodes(g, e[0], e[1], self_loops=False)
	for v in [k for k,v in comms.items() if v == comms[e[0]]]:
		comms[v] = comms[e[1]]
	print(e)
	draw_comm_graph(G, comms)

################################################################################
# Agglomerative Procedures: Label Propagation

comms = {}
for v in G.nodes():
	comms[v] = int(v)

updates = 1
while updates > 0:
	updates = 0
	for v in sorted(G.nodes(), key=lambda k: random.random()):
		counts = {}
		for u in G.neighbors(v):
			if comms[u] not in dict.keys(counts):
				counts[comms[u]] = 1
			else:
				counts[comms[u]] += 1
		
		c = np.random.choice([k for k in counts.keys() if counts[k]==max(counts.values())])
		if c != comms[v]:
			comms[v] = c
			updates += 1
	print(updates)
	draw_comm_graph(G, comms)

################################################################################
# Divisive Procedures: Girvan-Newman

g = G.copy()
while len(g.edges()) > 0:
	B = nx.edge_betweenness_centrality(g)
	b = sorted(B.items(), key=operator.itemgetter(1), reverse=True)[0]
	if b[1] == 0:
		break
		
	e = b[0]
	g.remove_edge(e[0], e[1])
	nx.draw(g, with_labels=True)
	plt.show()

