2026-09-30 14:30:08 +03:00
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
import networkx as nx
|
2026-09-30 20:56:36 +03:00
|
|
|
import pandas as pd
|
|
|
|
|
|
2026-10-24 20:31:25 +03:00
|
|
|
write_files = False
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
n = 0
|
2026-09-30 20:56:36 +03:00
|
|
|
nn_total_levels = 0
|
2026-09-30 14:30:08 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
def y(i):
|
2026-10-25 19:57:20 +02:00
|
|
|
# backwards compatibility
|
|
|
|
|
if i.__class__ == str:
|
|
|
|
|
i = int(i.split('-')[0])
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
return i % round(nn_total_levels ** 0.5)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
def x(i):
|
2026-10-25 19:57:20 +02:00
|
|
|
# backwards compatibility
|
|
|
|
|
if i.__class__ == str:
|
|
|
|
|
i = int(i.split('-')[0])
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
return i // round(nn_total_levels ** 0.5)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
def xy(i):
|
|
|
|
|
return x(i), y(i)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
def i(x, y):
|
|
|
|
|
return x * round(nn_total_levels ** 0.5) + y
|
|
|
|
|
|
|
|
|
|
def nn(*args):
|
|
|
|
|
if len(args) == 2:
|
|
|
|
|
# legacy_mode
|
|
|
|
|
cluster_no = args[0]
|
|
|
|
|
node_name = args[1]
|
|
|
|
|
|
|
|
|
|
if not nn_total_levels:
|
|
|
|
|
return str(cluster_no) + '-' + node_name
|
|
|
|
|
|
|
|
|
|
return str(cluster_no % nn_total_levels) + '-' + node_name
|
|
|
|
|
else:
|
|
|
|
|
# modern mode
|
|
|
|
|
x = args[0]
|
|
|
|
|
y = args[1]
|
|
|
|
|
l = args[2]
|
|
|
|
|
|
|
|
|
|
return str(i(x, y)) + '-' + l
|
2026-09-30 20:56:36 +03:00
|
|
|
|
2026-10-01 22:17:45 +03:00
|
|
|
def join_nodes(g, a, b, target_degree = 6):
|
2026-10-27 20:01:18 +02:00
|
|
|
if a == b:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if not (g.degree[a] >= target_degree or g.degree[b] >= target_degree):
|
2026-09-30 20:56:36 +03:00
|
|
|
g.add_edge(a, b)
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
if g.degree[a] > target_degree or g.degree[b] > target_degree:
|
|
|
|
|
g.remove_edge(a, b)
|
|
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
def start_file(p):
|
2026-10-24 20:31:25 +03:00
|
|
|
if not write_files:
|
|
|
|
|
return
|
|
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C']
|
|
|
|
|
open(p, 'w').write(','.join(index) + '\n')
|
|
|
|
|
|
|
|
|
|
def write_file(p, data):
|
2026-10-24 20:31:25 +03:00
|
|
|
if not write_files:
|
|
|
|
|
return
|
|
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C']
|
|
|
|
|
open(p, 'a').write(','.join([str(data[i]) for i in index]) + '\n')
|
2026-09-30 14:30:08 +03:00
|
|
|
|
|
|
|
|
def build_cluster(n):
|
|
|
|
|
g = nx.Graph()
|
2026-10-27 20:01:18 +02:00
|
|
|
nodes = ['ll', 'lu', 'lr', 'ld', 'rl', 'ru', 'rr', 'rd']
|
|
|
|
|
edges = [('ll', 'lu'), ('lu', 'lr'), ('lr', 'ld'), ('ld', 'll'),
|
|
|
|
|
('rl', 'ru'), ('ru', 'rr'), ('rr', 'rd'), ('rd', 'rl'),
|
|
|
|
|
('lu', 'ru'), ('ld', 'rd'), ('ll', 'lr'), ('rl', 'rr')]
|
2026-09-30 14:30:08 +03:00
|
|
|
|
|
|
|
|
g.add_nodes_from([nn(n, x) for x in nodes])
|
|
|
|
|
g.add_edges_from([tuple(nn(n, y) for y in x) for x in edges])
|
|
|
|
|
|
|
|
|
|
return g
|
|
|
|
|
|
2026-10-25 19:57:20 +02:00
|
|
|
def total_clusters(s):
|
|
|
|
|
return 2 ** s - 1
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
def build_network(l_n):
|
|
|
|
|
class P():
|
|
|
|
|
def __init__(self, x, y):
|
|
|
|
|
self.x = x
|
|
|
|
|
self.y = y
|
2026-09-30 19:00:53 +03:00
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
g = build_cluster(0)
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
global n, nn_total_levels
|
|
|
|
|
n = l_n
|
|
|
|
|
nn_total_levels = l_n ** 2
|
2026-09-30 20:56:36 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
for j in range(1, nn_total_levels):
|
|
|
|
|
c = build_cluster(j)
|
2026-09-30 14:30:08 +03:00
|
|
|
g = nx.union(g, c)
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
for x in range(n):
|
|
|
|
|
for y in range(n):
|
|
|
|
|
# regular grid
|
|
|
|
|
if x < n - 1:
|
|
|
|
|
join_nodes(g, nn(x, y, 'lr'), nn(x + 1, y, 'rl'))
|
|
|
|
|
join_nodes(g, nn(x, y, 'rr'), nn(x + 1, y, 'll'))
|
2026-09-30 14:30:08 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
if y < n - 1:
|
|
|
|
|
join_nodes(g, nn(x, y, 'lu'), nn(x, y + 1, 'rd'))
|
|
|
|
|
join_nodes(g, nn(x, y, 'ru'), nn(x, y + 1, 'ld'))
|
2026-09-30 19:00:53 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
# corner cross
|
|
|
|
|
join_nodes(g, nn(0, 0, 'lu'), nn(n // 2, n // 2, 'lu'))
|
|
|
|
|
join_nodes(g, nn(n // 2, n // 2, 'ld'), nn(n - 1, n - 1, 'ld'))
|
2026-09-30 19:00:53 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
join_nodes(g, nn(n - 1, 0, 'ru'), nn(n // 2, n // 2, 'ru'))
|
|
|
|
|
join_nodes(g, nn(n // 2, n // 2, 'rd'), nn(0, n - 1, 'rd'))
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
# grid fill
|
|
|
|
|
i = 0
|
|
|
|
|
while True:
|
|
|
|
|
start = P(n // 2 ** (1 + i) - 1 + n % 2, 0)
|
|
|
|
|
step = n // 2 ** (1 + i) - 1 + n % 2
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
if step == 0:
|
|
|
|
|
#print(f'Breaking at {i}')
|
|
|
|
|
break
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
while True:
|
|
|
|
|
#for _ in range(2*i+1):
|
|
|
|
|
y = start.y
|
|
|
|
|
while y + step < n:
|
|
|
|
|
#print('---', i, start.x, y, step, y + step, n)
|
|
|
|
|
if step == 0:
|
|
|
|
|
exit(1)
|
|
|
|
|
join_nodes(g, nn(start.x, y, 'll'), nn(start.x - step, y + step, 'll'))
|
|
|
|
|
join_nodes(g, nn(start.x, y, 'rr'), nn(start.x + step, y + step, 'rr'))
|
|
|
|
|
y += step * 2
|
|
|
|
|
join_nodes(g, nn(start.x, y, 'lr'), nn(start.x - step, y - step, 'lr'))
|
|
|
|
|
join_nodes(g, nn(start.x, y, 'rl'), nn(start.x + step, y - step, 'rl'))
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
start.x += step * 2
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
if start.x + step >= n:
|
|
|
|
|
break
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
i += 1
|
|
|
|
|
#visualize(g)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
# inline skips
|
|
|
|
|
for x in range(n):
|
|
|
|
|
for y in range(n):
|
|
|
|
|
join_nodes(g, nn(x, y, 'ld'), nn((x + n//2) % n, y, 'ld'))
|
|
|
|
|
join_nodes(g, nn(x, y, 'rd'), nn((x + n//3) % n, y, 'rd'))
|
2026-10-25 21:05:38 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
join_nodes(g, nn(x, y, 'lu'), nn(x, (y + n//5) % n, 'lu'))
|
|
|
|
|
join_nodes(g, nn(x, y, 'ru'), nn(x, (y + n//6) % n, 'ru'))
|
2026-09-30 19:00:53 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
join_nodes(g, nn(x, y, 'll'), nn((x + round(n//3)) % n, (y + round(n//3)) % n, 'll'))
|
|
|
|
|
join_nodes(g, nn(x, y, 'rr'), nn((x + round(n//2)) % n, (y + round(n//2)) % n, 'rr'))
|
|
|
|
|
|
2026-10-29 16:55:51 +02:00
|
|
|
join_nodes(g, nn(x, y, 'lr'), nn((x + round(n//5)) % n, (y - round(n//5)) % n, 'lr'))
|
|
|
|
|
join_nodes(g, nn(x, y, 'rl'), nn((x + round(n//6)) % n, (y - round(n//6)) % n, 'rl'))
|
2026-10-25 21:05:38 +02:00
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
return g
|
2026-09-30 14:30:08 +03:00
|
|
|
|
|
|
|
|
def analyze(G: nx.Graph) -> dict:
|
|
|
|
|
N = G.number_of_nodes()
|
|
|
|
|
E = G.number_of_edges()
|
|
|
|
|
degs = G.degree()
|
|
|
|
|
s_vals = [s[1] for s in degs]
|
|
|
|
|
S = max(s_vals)
|
|
|
|
|
D = nx.diameter(G)
|
|
|
|
|
D_average = nx.average_shortest_path_length(G)
|
|
|
|
|
Q = N*D_average/E
|
|
|
|
|
C = N*D*S
|
|
|
|
|
return {
|
|
|
|
|
'N': N,
|
|
|
|
|
'E': E,
|
2026-09-30 20:56:36 +03:00
|
|
|
'S': S,
|
|
|
|
|
'D': D,
|
|
|
|
|
'D_avg': round(D_average, 4),
|
|
|
|
|
'T': round(Q, 4),
|
|
|
|
|
'C': C,
|
2026-09-30 14:30:08 +03:00
|
|
|
}
|
|
|
|
|
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-01 22:17:45 +03:00
|
|
|
def visualize(g):
|
2026-10-27 20:01:18 +02:00
|
|
|
def draw_edges_between(a, b, x_min = 0, x_max = False, y_min = 0, y_max = False, color = 'black', width = 1.0, debug = False, direct = False, fmode = True, fmask = [1, 1, 1, 1], fsplit = False):
|
2026-10-01 22:17:45 +03:00
|
|
|
edgelist = [e for e in g.edges() if all([True if (a in i) or (b in i) else False for i in e])]
|
2026-10-27 20:01:18 +02:00
|
|
|
edgelist_filtered = []
|
2026-10-01 22:17:45 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
for i in edgelist:
|
|
|
|
|
pa, pb = i
|
2026-10-01 22:17:45 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
constraints = [True] * 4
|
|
|
|
|
|
|
|
|
|
if (x_max.__class__ != bool) and (abs(x(pa) - x(pb)) > x_max):
|
|
|
|
|
constraints[1] = False
|
|
|
|
|
|
|
|
|
|
if (y_max.__class__ != bool) and (abs(y(pa) - y(pb)) > y_max):
|
|
|
|
|
constraints[3] = False
|
|
|
|
|
|
|
|
|
|
if abs(x(pa) - x(pb)) < x_min:
|
|
|
|
|
constraints[0] = False
|
|
|
|
|
|
|
|
|
|
if abs(y(pa) - y(pb)) < y_min:
|
|
|
|
|
constraints[2] = False
|
|
|
|
|
|
|
|
|
|
#filt = [v for k, v in enumerate(constraints) if fmask[k]]
|
|
|
|
|
if fsplit:
|
|
|
|
|
if any([all(constraints[:2]), all(constraints[2:])]):
|
|
|
|
|
edgelist_filtered.append(i)
|
|
|
|
|
else:
|
|
|
|
|
if all(constraints):
|
|
|
|
|
edgelist_filtered.append(i)
|
|
|
|
|
|
|
|
|
|
#if fmode:
|
|
|
|
|
# if all(filt):
|
|
|
|
|
# edgelist_filtered.append(i)
|
|
|
|
|
#else:
|
|
|
|
|
# if any(filt):
|
|
|
|
|
# edgelist_filtered.append(i)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-01 22:17:45 +03:00
|
|
|
if direct:
|
2026-10-27 20:01:18 +02:00
|
|
|
nx.draw_networkx_edges(g, exp_pos, edgelist = edgelist_filtered, width = width, edge_color = color)
|
2026-10-01 22:17:45 +03:00
|
|
|
else:
|
2026-10-27 20:01:18 +02:00
|
|
|
nx.draw_networkx_edges(g, exp_pos, edgelist = edgelist_filtered, connectionstyle='arc3,rad=0.2', arrows=True, width = width, edge_color = color)
|
2026-10-01 22:17:45 +03:00
|
|
|
|
|
|
|
|
pos = {
|
2026-10-27 20:01:18 +02:00
|
|
|
'll': (-3, 0),
|
|
|
|
|
'lu': (-2, 1),
|
|
|
|
|
'lr': (-1, 0),
|
|
|
|
|
'ld': (-2, -1),
|
|
|
|
|
'rl': (1, 0),
|
|
|
|
|
'ru': (2, 1),
|
|
|
|
|
'rr': (3, 0),
|
|
|
|
|
'rd': (2, -1)
|
2026-10-01 22:17:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exp_pos = {}
|
|
|
|
|
|
|
|
|
|
for i in range(nn_total_levels):
|
|
|
|
|
for j, v in pos.items():
|
2026-10-25 19:57:20 +02:00
|
|
|
from math import log
|
2026-10-27 20:01:18 +02:00
|
|
|
bx, by = xy(i)
|
|
|
|
|
exp_pos[nn(i, j)] = (v[0] + bx * 8, v[1] + by * 3)
|
2026-10-01 22:17:45 +03:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
nx.draw_networkx_nodes(g, exp_pos, node_size = 100)
|
|
|
|
|
nx.draw_networkx_labels(g, exp_pos, font_size = 3)
|
2026-10-01 22:17:45 +03:00
|
|
|
|
|
|
|
|
# cluster
|
2026-10-27 20:01:18 +02:00
|
|
|
draw_edges_between('', '', x_max = 0, y_max = 0, color = '#888888', width = 0.5, direct = True)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
# regular grid
|
|
|
|
|
draw_edges_between('', '', x_min = 1, x_max = 1, y_min = 1, y_max = 1, color = '#FF0000', width = 2.0, fsplit = True)
|
2026-10-25 19:57:20 +02:00
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
# anything (debug)
|
|
|
|
|
draw_edges_between('', '', x_min = 1, y_min = 1, color = '#00FF00', width = 2.0, direct = True)
|
2026-10-01 22:17:45 +03:00
|
|
|
|
|
|
|
|
plt.show()
|
|
|
|
|
|
2026-09-30 14:30:08 +03:00
|
|
|
def main():
|
2026-10-24 20:31:25 +03:00
|
|
|
global write_files
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
write_files = False
|
2026-10-24 20:31:25 +03:00
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
i = 0
|
|
|
|
|
|
|
|
|
|
start_file('data.csv')
|
|
|
|
|
d = None
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
i += 1
|
|
|
|
|
g = build_network(i)
|
|
|
|
|
|
|
|
|
|
r = analyze(g)
|
|
|
|
|
r.update({"i": i})
|
|
|
|
|
|
|
|
|
|
print(r)
|
|
|
|
|
write_file('data.csv', r)
|
|
|
|
|
|
2026-10-27 20:01:18 +02:00
|
|
|
if g.number_of_nodes() > 2000:
|
2026-09-30 20:56:36 +03:00
|
|
|
break
|
2026-09-30 14:30:08 +03:00
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
def test():
|
|
|
|
|
g = build_network(15)
|
|
|
|
|
print(analyze(g))
|
|
|
|
|
print([i for i, v in g.degree if v > 6])
|
|
|
|
|
print(g.adj['14-ld'])
|
2026-09-30 19:00:53 +03:00
|
|
|
nx.draw(g, with_labels = True)
|
|
|
|
|
plt.show()
|
2026-09-30 14:30:08 +03:00
|
|
|
|
2026-09-30 20:56:36 +03:00
|
|
|
def test2():
|
2026-10-01 22:17:45 +03:00
|
|
|
g = build_network(144)
|
2026-09-30 20:56:36 +03:00
|
|
|
print(analyze(g))
|
|
|
|
|
print(set([v for i, v in g.degree()]))
|
|
|
|
|
|
2026-10-01 22:17:45 +03:00
|
|
|
def test3():
|
2026-10-27 20:01:18 +02:00
|
|
|
g = build_network(9)
|
2026-10-01 22:17:45 +03:00
|
|
|
visualize(g)
|
|
|
|
|
|
2026-09-30 14:30:08 +03:00
|
|
|
if __name__=="__main__":
|
2026-10-25 19:57:20 +02:00
|
|
|
#test3()
|
|
|
|
|
main()
|