7 Commits
Author SHA1 Message Date
hasslesstech 7b5f6b93d8 lab3-rc2 2026-10-29 19:41:56 +02:00
hasslesstech 96a2614a9f improve efficiency 2026-10-29 16:55:51 +02:00
hasslesstech 84a6ff03c2 lab3-rc1 2026-10-27 20:01:18 +02:00
hasslesstech 75a8ba37c8 yet another performance improvement 2026-10-25 21:31:06 +02:00
hasslesstech 3077e14c07 yet another performance improvement 2026-10-25 21:05:38 +02:00
hasslesstech 8af4bb0b99 update for lab2 2026-10-25 19:57:20 +02:00
hasslesstech 538e7b7784 clean up after lab1 2026-10-24 20:31:25 +03:00
+200 -136
View File
@@ -2,89 +2,175 @@ import matplotlib.pyplot as plt
import networkx as nx
import pandas as pd
write_files = False
n = 0
nn_total_levels = 0
def nn(cluster_no, node_name):
edge_groups = {}
def y(i):
# backwards compatibility
if i.__class__ == str:
i = int(i.split('-')[0])
return i % round(nn_total_levels ** 0.5)
def x(i):
# backwards compatibility
if i.__class__ == str:
i = int(i.split('-')[0])
return i // round(nn_total_levels ** 0.5)
def xy(i):
return x(i), y(i)
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]
def lvl(node_name):
return int(node_name.split('-')[0])
return str(i(x, y)) + '-' + l
def join_nodes(g, a, b, target_degree = 6):
if not (g.degree[a] == target_degree or g.degree[b] == target_degree):
def join_nodes(g, a, b, group = 'default', target_degree = 6):
if a == b:
return
if not (g.degree[a] >= target_degree or g.degree[b] >= target_degree):
g.add_edge(a, b)
if g.degree[a] > target_degree or g.degree[b] > target_degree:
g.remove_edge(a, b)
return
if group not in edge_groups:
edge_groups[group] = []
edge_groups[group].append((a, b))
def start_file(p):
if not write_files:
return
index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C']
open(p, 'w').write(','.join(index) + '\n')
def write_file(p, data):
if not write_files:
return
index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C']
open(p, 'a').write(','.join([str(data[i]) for i in index]) + '\n')
def build_cluster(n):
g = nx.Graph()
nodes = ['ls', 'lu', 'ld', 'm', 'rd', 'ru', 'rs']
edges = [('ls', 'lu'), ('ls', 'ld'), ('ld', 'lu'),
('rs', 'ru'), ('rs', 'rd'), ('rd', 'ru'),
('lu', 'm'), ('ld', 'm'),
('ru', 'm'), ('rd', 'm')]
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')]
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
def build_network(n):
throw_dist = 4
def total_clusters(s):
return 2 ** s - 1
def build_network(l_n):
class P():
def __init__(self, x, y):
self.x = x
self.y = y
g = build_cluster(0)
global nn_total_levels
nn_total_levels = n
global n, nn_total_levels
n = l_n
nn_total_levels = l_n ** 2
for i in range(1, n):
c = build_cluster(i)
for j in range(1, nn_total_levels):
c = build_cluster(j)
g = nx.union(g, c)
for i in range(n):
if n >= 2:
if i % 2:
join_nodes(g, nn(i, 'lu'), nn(i-1, 'lu'), 4)
join_nodes(g, nn(i, 'rd'), nn(i-1, 'rd'), 4)
else:
join_nodes(g, nn(i, 'ld'), nn(i-1, 'ld'), 4)
join_nodes(g, nn(i, 'ru'), nn(i-1, 'ru'), 4)
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'))
g.add_edge(nn(i, 'ls'), nn(i-1, 'rs'))
g.add_edge(nn(i, 'rs'), nn(i-1, 'ls'))
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'))
if n > 1 * throw_dist:
g.add_edge(nn(i, 'rs'), nn(i-(1*throw_dist), 'ls'))
g.add_edge(nn(i, 'ls'), nn(i-(1*throw_dist), 'rs'))
# 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'))
if n > 2 * throw_dist:
a = nn(i, 'lu')
b = nn(i-(2*throw_dist), 'lu')
join_nodes(g, a, b)
if n > 3 * throw_dist:
a = nn(i, 'ld')
b = nn(i-(3*throw_dist), 'ld')
join_nodes(g, a, b)
if n > 4 * throw_dist:
a = nn(i, 'ru')
b = nn(i-(4*throw_dist), 'ru')
join_nodes(g, a, b)
if n > 5 * throw_dist:
a = nn(i, 'rd')
b = nn(i-(5*throw_dist), 'rd')
join_nodes(g, a, b)
if n > 7 * throw_dist:
a = nn(i, 'm')
b = nn(i-(7*throw_dist), 'm')
join_nodes(g, a, b)
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'))
# grid fill
i = 0
while True:
start = P(n // 2 ** (1 + i) - 1 + n % 2, 0)
step = n // 2 ** (1 + i) - 1 + n % 2
if step == 0:
#print(f'Breaking at {i}')
break
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'), f"gf{i}")
join_nodes(g, nn(start.x, y, 'rr'), nn(start.x + step, y + step, 'rr'), f"gf{i}")
y += step * 2
join_nodes(g, nn(start.x, y, 'lr'), nn(start.x - step, y - step, 'lr'), f"gf{i}")
join_nodes(g, nn(start.x, y, 'rl'), nn(start.x + step, y - step, 'rl'), f"gf{i}")
start.x += step * 2
if start.x + step >= n:
break
i += 1
#visualize(g)
# 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'), "is1")
join_nodes(g, nn(x, y, 'rd'), nn((x + n//3) % n, y, 'rd'), "is2")
join_nodes(g, nn(x, y, 'lu'), nn(x, (y + n//5) % n, 'lu'), "is3")
join_nodes(g, nn(x, y, 'ru'), nn(x, (y + n//6) % n, 'ru'), "is4")
join_nodes(g, nn(x, y, 'll'), nn((x + round(n//3)) % n, (y + round(n//3)) % n, 'll'), "is5")
join_nodes(g, nn(x, y, 'rr'), nn((x + round(n//2)) % n, (y + round(n//2)) % n, 'rr'), "is6")
join_nodes(g, nn(x, y, 'lr'), nn((x + round(n//5)) % n, (y - round(n//5)) % n, 'lr'), "is7")
join_nodes(g, nn(x, y, 'rl'), nn((x + round(n//6)) % n, (y - round(n//6)) % n, 'rl'), "is8")
return g
@@ -108,104 +194,94 @@ def analyze(G: nx.Graph) -> dict:
'C': C,
}
def visualize(g):
def draw_edges_between(a, b, lvl_min = 0, lvl_max = False, color = 'black', width = 1.0, debug = False, direct = False):
def draw_edge_groups():
colors = ["#FF0000", "#00FF00", "#0000FF", "#AAAA00", "#BB00BB", "#1ab278", "#ea44fc", "#c9c204", "#49af5a", "#692c8e"]
for i, v in enumerate(edge_groups.values()):
nx.draw_networkx_edges(g, exp_pos, edgelist = v, connectionstyle='arc3,rad=0.2', arrows=True, width = 2.0, edge_color = colors[i % len(colors)])
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):
edgelist = [e for e in g.edges() if all([True if (a in i) or (b in i) else False for i in e])]
edgelist_filtered = []
if debug:
print(edgelist)
for i in edgelist:
pa, pb = i
if lvl_max.__class__ == bool:
if debug:
print("Running 1 branch")
constraints = [True] * 4
edgelist = [(pa, pb) for pa, pb in edgelist if not (abs(lvl(pa) - lvl(pb)) < lvl_min or nn_total_levels - abs(lvl(pa) - lvl(pb)) < lvl_min)]
'''
for p in edgelist:
if abs(lvl(pa) - lvl(pb)) < lvl_min:
edgelist.remove((pa, pb))
'''
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 debug:
print(f"Running 2 branch on {edgelist}")
if all(constraints):
edgelist_filtered.append(i)
edgelist = [(pa, pb) for pa, pb in edgelist if not ((abs(lvl(pa) - lvl(pb)) < lvl_min or nn_total_levels - abs(lvl(pa) - lvl(pb)) < lvl_min) or (abs(lvl(pa) - lvl(pb)) > lvl_max and nn_total_levels - abs(lvl(pa) - lvl(pb)) > lvl_max))]
'''
for pa, pb in edgelist:
if debug:
print(f"Processing ({pa}, {pb})")
if abs(lvl(pa) - lvl(pb)) < lvl_min or abs(lvl(pa) - lvl(pb)) > lvl_max:
edgelist.remove((pa, pb))
if debug:
print(f'Discarding {pa} <-> {pb} (lvl(pa) == {lvl(pa)}, lvl(pb) == {lvl(pb)})')
elif debug:
print(f'Leaving {pa} <-> {pb} (lvl(pa) == {lvl(pa)}, lvl(pb) == {lvl(pb)})')
for pa, pb in edgelist:
if debug:
print(f"Processing ({pa}, {pb})")
if abs(lvl(pa) - lvl(pb)) < lvl_min or abs(lvl(pa) - lvl(pb)) > lvl_max:
edgelist.remove((pa, pb))
if debug:
print(f'Discarding {pa} <-> {pb} (lvl(pa) == {lvl(pa)}, lvl(pb) == {lvl(pb)})')
elif debug:
print(f'Leaving {pa} <-> {pb} (lvl(pa) == {lvl(pa)}, lvl(pb) == {lvl(pb)})')
'''
if debug:
print(edgelist)
#if fmode:
# if all(filt):
# edgelist_filtered.append(i)
#else:
# if any(filt):
# edgelist_filtered.append(i)
if direct:
nx.draw_networkx_edges(g, exp_pos, edgelist = edgelist, width = width, edge_color = color)
nx.draw_networkx_edges(g, exp_pos, edgelist = edgelist_filtered, width = width, edge_color = color)
else:
nx.draw_networkx_edges(g, exp_pos, edgelist = edgelist, connectionstyle='arc3,rad=0.2', arrows=True, width = width, edge_color = color)
nx.draw_networkx_edges(g, exp_pos, edgelist = edgelist_filtered, connectionstyle='arc3,rad=0.2', arrows=True, width = width, edge_color = color)
pos = {
'ls': (-2, 0),
'lu': (-1, 1),
'ld': (-1, -1),
'm' : (0, 0),
'ru': (1, 1),
'rd': (1, -1),
'rs': (2, 0)
'll': (-3, 0),
'lu': (-2, 1),
'lr': (-1, 0),
'ld': (-2, -1),
'rl': (1, 0),
'ru': (2, 1),
'rr': (3, 0),
'rd': (2, -1)
}
exp_pos = {}
for i in range(nn_total_levels):
for j, v in pos.items():
exp_pos[nn(i, j)] = (v[0], v[1] * 0.65 + 3 * i)
from math import log
bx, by = xy(i)
exp_pos[nn(i, j)] = (v[0] + bx * 8, v[1] + by * 3)
nx.draw_networkx_nodes(g, exp_pos, node_size = 600)
nx.draw_networkx_labels(g, exp_pos, font_size = 8)
#nx.draw_networkx_edges(g, exp_pos, edgelist = [e for e in g.edges() if all([True if ('ls' in i) or ('rs' in i) else False for i in e])], connectionstyle='arc3,rad=0.2', arrows=True)
nx.draw_networkx_nodes(g, exp_pos, node_size = 100)
nx.draw_networkx_labels(g, exp_pos, font_size = 3)
# cluster
draw_edges_between('', '', lvl_max = 0, color = '#888888', width = 0.5, direct = True)
draw_edges_between('', '', x_max = 0, y_max = 0, color = '#888888', width = 0.5, direct = True)
# S => 4
draw_edges_between('ls', 'rs', lvl_max = 1, color = '#33AAAA', width = 2)
# regular grid
#draw_edges_between('', '', x_min = 1, x_max = 1, y_min = 1, y_max = 1, color = '#FF0000', width = 2.0, fsplit = True)
draw_edges_between('lu', 'lu', lvl_max = 1, color = '#AAAA33', width = 1)
draw_edges_between('ru', 'ru', lvl_max = 1, color = '#AAAA33', width = 1)
draw_edges_between('ld', 'ld', lvl_max = 1, color = '#AAAA33', width = 1)
draw_edges_between('rd', 'rd', lvl_max = 1, color = '#AAAA33', width = 1)
# anything (debug)
#draw_edges_between('', '', x_min = 1, y_min = 1, color = '#00FF00', width = 2.0, direct = True)
# S => 6
draw_edges_between('lu', 'lu', lvl_min = 2, color = '#FF0000', width = 1.5)
draw_edges_between('ld', 'ld', lvl_min = 2, color = '#FFFF00', width = 1.5)
draw_edges_between('ru', 'ru', lvl_min = 2, color = '#00FF00', width = 1.5)
draw_edges_between('rd', 'rd', lvl_min = 2, color = '#00FFFF', width = 1.5)
draw_edges_between('ls', 'ls', lvl_min = 2, color = '#0000FF', width = 1.5)
draw_edges_between('rs', 'rs', lvl_min = 2, color = '#FF00FF', width = 1.5)
draw_edges_between('m' , 'm' , lvl_min = 2, color = '#000000', width = 1.5)
draw_edge_groups()
plt.show()
def main():
global write_files
write_files = True
i = 0
start_file('data.csv')
@@ -218,25 +294,12 @@ def main():
r = analyze(g)
r.update({"i": i})
'''
if d.__class__ == None.__class__:
d = pd.DataFrame(r, index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C'])
else:
d.add(r)
'''
print(r)
write_file('data.csv', r)
if g.number_of_nodes() > 1000:
if g.number_of_nodes() > 2000:
break
#print(r)
#nx.draw(g, with_labels = True)
#plt.show()
#d.to_csv('data.csv')
def test():
g = build_network(15)
print(analyze(g))
@@ -251,9 +314,10 @@ def test2():
print(set([v for i, v in g.degree()]))
def test3():
g = build_network(3)
#print(g.adj['0-ls'])
g = build_network(2)
print(analyze(g))
visualize(g)
if __name__=="__main__":
test3()
#test3()
main()