2 Commits
Author SHA1 Message Date
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
+136 -118
View File
@@ -2,89 +2,138 @@ import matplotlib.pyplot as plt
import networkx as nx import networkx as nx
import pandas as pd import pandas as pd
write_files = False
nn_total_levels = 0 nn_total_levels = 0
def su(s):
return 2 ** (s + 1) - 1
def lvl(i):
# backwards compatibility
if i.__class__ == str:
i = int(i.split('-')[0])
y = 0
while i - su(y) >= 0:
y += 1
return y
def ps(i):
# backwards compatibility
if i.__class__ == str:
i = int(i.split('-')[0])
y = lvl(i)
return i - su(y-1)
def neigh(i, o):
y = lvl(i)
a = 2 ** y
i = i - su(y - 1)
return su(y - 1) + (i + o) % a
def nn(cluster_no, node_name): def nn(cluster_no, node_name):
if not nn_total_levels: if not nn_total_levels:
return str(cluster_no) + '-' + node_name return str(cluster_no) + '-' + node_name
return str(cluster_no % nn_total_levels) + '-' + node_name return str(cluster_no % nn_total_levels) + '-' + node_name
def lvl(node_name):
return int(node_name.split('-')[0])
def join_nodes(g, a, b, target_degree = 6): def join_nodes(g, a, b, target_degree = 6):
if not (g.degree[a] == target_degree or g.degree[b] == target_degree): if not (g.degree[a] == target_degree or g.degree[b] == target_degree):
g.add_edge(a, b) g.add_edge(a, b)
def start_file(p): def start_file(p):
if not write_files:
return
index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C'] index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C']
open(p, 'w').write(','.join(index) + '\n') open(p, 'w').write(','.join(index) + '\n')
def write_file(p, data): def write_file(p, data):
if not write_files:
return
index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C'] index = ['i', 'N', 'E', 'S', 'D', 'D_avg', 'T', 'C']
open(p, 'a').write(','.join([str(data[i]) for i in index]) + '\n') open(p, 'a').write(','.join([str(data[i]) for i in index]) + '\n')
def build_cluster(n): def build_cluster(n):
g = nx.Graph() g = nx.Graph()
nodes = ['ls', 'lu', 'ld', 'm', 'rd', 'ru', 'rs'] nodes = ['ls', 'lu', 'lm', 'ld', 'm', 'rs', 'ru', 'rm', 'rd']
edges = [('ls', 'lu'), ('ls', 'ld'), ('ld', 'lu'), edges = [('ls', 'lu'), ('lu', 'm'), ( 'm', 'ld'), ('ld', 'ls'),
('rs', 'ru'), ('rs', 'rd'), ('rd', 'ru'), ('ls', 'lm'), ('lu', 'lm'), ( 'm', 'lm'), ('ld', 'lm'),
('lu', 'm'), ('ld', 'm'), ('rs', 'ru'), ('ru', 'm'), ( 'm', 'rd'), ('rd', 'rs'),
('ru', 'm'), ('rd', 'm')] ('rs', 'rm'), ('ru', 'rm'), ( 'm', 'rm'), ('rd', 'rm'),
('lu', 'ru'), ('ld', 'rd')]
g.add_nodes_from([nn(n, x) for x in nodes]) 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]) g.add_edges_from([tuple(nn(n, y) for y in x) for x in edges])
return g return g
def total_clusters(s):
return 2 ** s - 1
def build_network(n): def build_network(n):
throw_dist = 4 throw_dist = 4
g = build_cluster(0) g = build_cluster(0)
global nn_total_levels global nn_total_levels
nn_total_levels = n nn_total_levels = total_clusters(n)
for i in range(1, n): for i in range(1, nn_total_levels):
c = build_cluster(i) c = build_cluster(i)
g = nx.union(g, c) g = nx.union(g, c)
for i in range(n): for l_lvl in range(n):
if n >= 2: for c in range(2 ** l_lvl):
if i % 2: i = total_clusters(l_lvl) + c
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)
g.add_edge(nn(i, 'ls'), nn(i-1, 'rs')) # child nodes
g.add_edge(nn(i, 'rs'), nn(i-1, 'ls')) cl = total_clusters(l_lvl + 1) + 2 * c
cr = total_clusters(l_lvl + 1) + 2 * c + 1
if n > 1 * throw_dist: # child nodes ^ 2 crossed
g.add_edge(nn(i, 'rs'), nn(i-(1*throw_dist), 'ls')) ccl = total_clusters(l_lvl + 2) + 4 * c + 1
g.add_edge(nn(i, 'ls'), nn(i-(1*throw_dist), 'rs')) ccr = total_clusters(l_lvl + 2) + 4 * c + 2
if n > 2 * throw_dist: # child nodes ^ 3 straight
a = nn(i, 'lu') cccl = total_clusters(l_lvl + 3) + 8 * c
b = nn(i-(2*throw_dist), 'lu') cccr = total_clusters(l_lvl + 3) + 8 * c + 7
join_nodes(g, a, b)
if n > 3 * throw_dist: # child nodes ^ 4 crossed
a = nn(i, 'ld') ccccl = total_clusters(l_lvl + 4) + 16 * c + 5
b = nn(i-(3*throw_dist), 'ld') ccccr = total_clusters(l_lvl + 4) + 16 * c + 13
join_nodes(g, a, b)
if n > 4 * throw_dist: # child nodes ^ 5 crimped
a = nn(i, 'ru') cccccl = total_clusters(l_lvl + 4) + 32 * c + 9
b = nn(i-(4*throw_dist), 'ru') cccccr = total_clusters(l_lvl + 4) + 32 * c + 25
join_nodes(g, a, b)
if n > 5 * throw_dist: # regular set 1
a = nn(i, 'rd') if l_lvl < n - 1:
b = nn(i-(5*throw_dist), 'rd') join_nodes(g, nn(i, 'lm'), nn(cl, 'rm'))
join_nodes(g, a, b) join_nodes(g, nn(i, 'rm'), nn(cr, 'lm'))
if n > 7 * throw_dist:
a = nn(i, 'm') # irregular: grid ???
b = nn(i-(7*throw_dist), 'm') if l_lvl < n - 2:
join_nodes(g, a, b) join_nodes(g, nn(i, 'lu'), nn(ccl, 'rd'))
join_nodes(g, nn(i, 'ru'), nn(ccr, 'ld'))
# irregular: grid ?????
if l_lvl < n - 3:
join_nodes(g, nn(i, 'ld'), nn(cccl, 'ru'))
join_nodes(g, nn(i, 'rd'), nn(cccr, 'lu'))
# irregulars: inline skips
#if lvl(i) == lvl(i + l_lvl) and l_lvl:
join_nodes(g, nn(i, 'ru'), nn(neigh(i, +l_lvl), 'rd'))
#if lvl(i) == lvl(i - l_lvl) and l_lvl:
join_nodes(g, nn(i, 'lu'), nn(neigh(i, -l_lvl * 2), 'ld'))
# irregular: inline ring
join_nodes(g, nn(i, 'rs'), nn(neigh(i, +1), 'ls'), 5)
join_nodes(g, nn(i, 'ls'), nn(neigh(i, -1), 'rs'), 5)
return g return g
@@ -108,54 +157,35 @@ def analyze(G: nx.Graph) -> dict:
'C': C, 'C': C,
} }
def get_cluster_base_coords(cluster_i):
if cluster_i == 0:
return 0, 0
y = lvl(cluster_i)
s = 2 ** (2-y)
r = 0
for i in range(y):
r += 2 ** -i
x = r + (cluster_i - su(y) + 1) * s
return x, float(y)
def visualize(g): 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_edges_between(a, b, lvl_min = 0, lvl_max = False, ps_min = 0, ps_max = False, color = 'black', width = 1.0, debug = False, direct = 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 = [e for e in g.edges() if all([True if (a in i) or (b in i) else False for i in e])]
if debug:
print(edgelist)
if lvl_max.__class__ == bool: if lvl_max.__class__ == bool:
if debug:
print("Running 1 branch")
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)] 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))
'''
else: else:
if debug:
print(f"Running 2 branch on {edgelist}")
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))] 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: if ps_max.__class__ == bool:
edgelist.remove((pa, pb)) edgelist = [(pa, pb) for pa, pb in edgelist if not (abs(ps(pa) - ps(pb)) < ps_min or nn_total_levels - abs(ps(pa) - ps(pb)) < ps_min)]
if debug: else:
print(f'Discarding {pa} <-> {pb} (lvl(pa) == {lvl(pa)}, lvl(pb) == {lvl(pb)})') edgelist = [(pa, pb) for pa, pb in edgelist if not ((abs(ps(pa) - ps(pb)) < ps_min or nn_total_levels - abs(ps(pa) - ps(pb)) < ps_min) or (abs(ps(pa) - ps(pb)) > ps_max and nn_total_levels - abs(ps(pa) - ps(pb)) > ps_max))]
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 direct: 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, width = width, edge_color = color)
@@ -166,7 +196,9 @@ def visualize(g):
'ls': (-2, 0), 'ls': (-2, 0),
'lu': (-1, 1), 'lu': (-1, 1),
'ld': (-1, -1), 'ld': (-1, -1),
'lm': (-1, 0),
'm' : (0, 0), 'm' : (0, 0),
'rm': (1, 0),
'ru': (1, 1), 'ru': (1, 1),
'rd': (1, -1), 'rd': (1, -1),
'rs': (2, 0) 'rs': (2, 0)
@@ -176,36 +208,35 @@ def visualize(g):
for i in range(nn_total_levels): for i in range(nn_total_levels):
for j, v in pos.items(): 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 = get_cluster_base_coords(i)
scaler = (log(nn_total_levels, 2) + 1) * 2
exp_pos[nn(i, j)] = (v[0] + bx * scaler, v[1] + by * 3.5)
nx.draw_networkx_nodes(g, exp_pos, node_size = 600) nx.draw_networkx_nodes(g, exp_pos, node_size = 600)
nx.draw_networkx_labels(g, exp_pos, font_size = 8) 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)
# cluster # cluster
draw_edges_between('', '', lvl_max = 0, color = '#888888', width = 0.5, direct = True) draw_edges_between('', '', lvl_max = 0, ps_max = 0, color = '#888888', width = 0.5, direct = True)
# S => 4 # basic tree
draw_edges_between('ls', 'rs', lvl_max = 1, color = '#33AAAA', width = 2) draw_edges_between('', '', lvl_min = 1, lvl_max = 1, color = '#FF0000', width = 2.0)
draw_edges_between('lu', 'lu', lvl_max = 1, color = '#AAAA33', width = 1) # inline ring links
draw_edges_between('ru', 'ru', lvl_max = 1, color = '#AAAA33', width = 1) draw_edges_between('ls', 'rs', lvl_max = 0, ps_min = 1, color = '#00FF00', width = 2.0)
draw_edges_between('ld', 'ld', lvl_max = 1, color = '#AAAA33', width = 1) draw_edges_between('lu', 'ld', lvl_max = 0, ps_min = 1, color = '#0000FF', width = 2.0)
draw_edges_between('rd', 'rd', lvl_max = 1, color = '#AAAA33', width = 1) draw_edges_between('ru', 'rd', lvl_max = 0, ps_min = 1, color = '#AA00AA', width = 2.0)
# S => 6 # grid links
draw_edges_between('lu', 'lu', lvl_min = 2, color = '#FF0000', width = 1.5) draw_edges_between('', '', lvl_min = 2, color = '#AAAA00', width = 2.0)
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)
plt.show() plt.show()
def main(): def main():
global write_files
write_files = True
i = 0 i = 0
start_file('data.csv') start_file('data.csv')
@@ -218,25 +249,12 @@ def main():
r = analyze(g) r = analyze(g)
r.update({"i": i}) 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) print(r)
write_file('data.csv', r) write_file('data.csv', r)
if g.number_of_nodes() > 1000: if g.number_of_nodes() > 3000:
break break
#print(r)
#nx.draw(g, with_labels = True)
#plt.show()
#d.to_csv('data.csv')
def test(): def test():
g = build_network(15) g = build_network(15)
print(analyze(g)) print(analyze(g))
@@ -251,9 +269,9 @@ def test2():
print(set([v for i, v in g.degree()])) print(set([v for i, v in g.degree()]))
def test3(): def test3():
g = build_network(3) g = build_network(7)
#print(g.adj['0-ls'])
visualize(g) visualize(g)
if __name__=="__main__": if __name__=="__main__":
test3() #test3()
main()