import networkx as nx
import numpy as np
import scipy as sp
import scipy.cluster.vq as vq
import matplotlib.pyplot as plt
import math
import random
import operator
from networkx import graph_atlas_g

################################################################################
# Read in our benchmark graph
G = nx.read_edgelist("karate.data", comments="%")
G = nx.read_edgelist("karate.data", comments="%")
n = G.order()
m = G.size()
p = m / (n*(n-1) / 2)
D = sorted((d for n, d in G.degree()), reverse=True)

################################################################################
# Let's generate some random graphs that 'model' G

# Erdos-Renyi
G_er = nx.erdos_renyi_graph(n, p)

# Configuration model
G_cm = nx.simple_graph(nx.configuration_model(D))

# Chung-Lu
G_cl = nx.expected_degree_graph(D)


################################################################################
# Compare degree distributions

fig = plt.figure()
ax = fig.add_subplot(111)
for g in list([G, G_er, G_cm, G_cl]):
  degree_dist = nx.degree_histogram(g)
  ax.plot(degree_dist)

ax.legend(["G", "ER", "CM", "CL"])
plt.show()


################################################################################
# Compare clustering coefficients

cc_g  = nx.average_clustering(G)
cc_er = nx.average_clustering(G_er)
cc_cm = nx.average_clustering(nx.Graph(G_cm))
cc_cl = nx.average_clustering(G_cl)

plt.bar(list(["G", "ER", "CM", "CL"]), list([cc_g, cc_er, cc_cm, cc_cl]))
plt.show()


################################################################################
# We can also do some subgraph frequency analysis

three_node_graphs = [g for g in graph_atlas_g() if len(g.nodes())==3 and len(list(nx.connected_components(g)))==1]
four_node_graphs = [g for g in graph_atlas_g() if len(g.nodes())==4 and len(list(nx.connected_components(g)))==1]

S_g = []
S_er = []
S_cm = []
S_cl = []

for g in three_node_graphs:
	nx.draw(g)
	plt.show()
	S_g.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G,g).subgraph_isomorphisms_iter())))
	S_er.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G_er,g).subgraph_isomorphisms_iter())))
	S_cm.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G_cm,g).subgraph_isomorphisms_iter())))
	S_cl.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G_cl,g).subgraph_isomorphisms_iter())))

for g in four_node_graphs:
	nx.draw(g)
	plt.show()
	S_g.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G,g).subgraph_isomorphisms_iter())))
	S_er.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G_er,g).subgraph_isomorphisms_iter())))
	S_cm.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G_cm,g).subgraph_isomorphisms_iter())))
	S_cl.append(len(list(nx.algorithms.isomorphism.GraphMatcher(G_cl,g).subgraph_isomorphisms_iter())))

graphs = ("3_path", "3_triangle", "4_star", "4_path", "4_tri_line", "4_cycle", "4_cycle_line", "4_clique")
sub_freqs = {
    'G': (S_g[0], S_g[1], S_g[2], S_g[3], S_g[4], S_g[5], S_g[6], S_g[7]),
    'ER': (S_er[0], S_er[1], S_er[2], S_er[3], S_er[4], S_er[5], S_er[6], S_er[7]),
    'CM': (S_cm[0], S_cm[1], S_cm[2], S_cm[3], S_cm[4], S_cm[5], S_cm[6], S_cm[7]),
    'CL': (S_cl[0], S_cl[1], S_cl[2], S_cl[3], S_cl[4], S_cl[5], S_cl[6], S_cl[7]),
}

x = np.arange(len(graphs))  # the label locations
width = 0.20  # the width of the bars
multiplier = 0

fig, ax = plt.subplots(layout='constrained')

for attribute, measurement in sub_freqs.items():
    offset = width * multiplier
    rects = ax.bar(x + offset, measurement, width, label=attribute)
    ax.bar_label(rects, padding=3)
    multiplier += 1

# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Subgraph frequency')
ax.set_title('Subgraph frequency analysis')
ax.set_xticks(x + width, graphs)
ax.legend(loc='upper left', ncols=4)
ax.set_ylim(0, 1000)
plt.show()


len(list(nx.algorithms.isomorphism.GraphMatcher(G,three_node_graphs[0]).subgraph_isomorphisms_iter()))