This commit is contained in:
2026-10-27 20:01:18 +02:00
parent 75a8ba37c8
commit 84a6ff03c2
+149 -126
View File
@@ -4,45 +4,57 @@ import pandas as pd
write_files = False write_files = False
n = 0
nn_total_levels = 0 nn_total_levels = 0
def su(s): def y(i):
return 2 ** (s + 1) - 1
def lvl(i):
# backwards compatibility # backwards compatibility
if i.__class__ == str: if i.__class__ == str:
i = int(i.split('-')[0]) i = int(i.split('-')[0])
y = 0 return i % round(nn_total_levels ** 0.5)
while i - su(y) >= 0:
y += 1
return y def x(i):
def ps(i):
# backwards compatibility # backwards compatibility
if i.__class__ == str: if i.__class__ == str:
i = int(i.split('-')[0]) i = int(i.split('-')[0])
y = lvl(i) return i // round(nn_total_levels ** 0.5)
return i - su(y-1)
def neigh(i, o): def xy(i):
y = lvl(i) return x(i), y(i)
a = 2 ** y
i = i - su(y - 1) def i(x, y):
return su(y - 1) + (i + o) % a 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]
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
else:
# modern mode
x = args[0]
y = args[1]
l = args[2]
return str(i(x, y)) + '-' + l
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 a == b:
return
if not (g.degree[a] >= target_degree or g.degree[b] >= target_degree):
g.add_edge(a, b) g.add_edge(a, b)
if g.degree[a] > target_degree or g.degree[b] > target_degree:
g.remove_edge(a, b)
def start_file(p): def start_file(p):
if not write_files: if not write_files:
return return
@@ -59,12 +71,10 @@ def write_file(p, data):
def build_cluster(n): def build_cluster(n):
g = nx.Graph() g = nx.Graph()
nodes = ['ls', 'lu', 'lm', 'ld', 'm', 'rs', 'ru', 'rm', 'rd'] nodes = ['ll', 'lu', 'lr', 'ld', 'rl', 'ru', 'rr', 'rd']
edges = [('ls', 'lu'), ('lu', 'm'), ( 'm', 'ld'), ('ld', 'ls'), edges = [('ll', 'lu'), ('lu', 'lr'), ('lr', 'ld'), ('ld', 'll'),
('ls', 'lm'), ('lu', 'lm'), ( 'm', 'lm'), ('ld', 'lm'), ('rl', 'ru'), ('ru', 'rr'), ('rr', 'rd'), ('rd', 'rl'),
('rs', 'ru'), ('ru', 'm'), ( 'm', 'rd'), ('rd', 'rs'), ('lu', 'ru'), ('ld', 'rd'), ('ll', 'lr'), ('rl', 'rr')]
('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])
@@ -74,73 +84,85 @@ def build_cluster(n):
def total_clusters(s): def total_clusters(s):
return 2 ** s - 1 return 2 ** s - 1
def build_network(n): def build_network(l_n):
throw_dist = 4 class P():
def __init__(self, x, y):
self.x = x
self.y = y
g = build_cluster(0) g = build_cluster(0)
global nn_total_levels global n, nn_total_levels
nn_total_levels = total_clusters(n) n = l_n
nn_total_levels = l_n ** 2
for i in range(1, nn_total_levels): for j in range(1, nn_total_levels):
c = build_cluster(i) c = build_cluster(j)
g = nx.union(g, c) g = nx.union(g, c)
for l_lvl in range(n): for x in range(n):
for c in range(2 ** l_lvl): for y in range(n):
i = total_clusters(l_lvl) + c # 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'))
# child nodes if y < n - 1:
cl = total_clusters(l_lvl + 1) + 2 * c join_nodes(g, nn(x, y, 'lu'), nn(x, y + 1, 'rd'))
cr = total_clusters(l_lvl + 1) + 2 * c + 1 join_nodes(g, nn(x, y, 'ru'), nn(x, y + 1, 'ld'))
# child nodes ^ 2 crossed # corner cross
ccl = total_clusters(l_lvl + 2) + 4 * c + 1 join_nodes(g, nn(0, 0, 'lu'), nn(n // 2, n // 2, 'lu'))
ccr = total_clusters(l_lvl + 2) + 4 * c + 2 join_nodes(g, nn(n // 2, n // 2, 'ld'), nn(n - 1, n - 1, 'ld'))
# child nodes ^ 3 straight join_nodes(g, nn(n - 1, 0, 'ru'), nn(n // 2, n // 2, 'ru'))
cccl = total_clusters(l_lvl + 3) + 8 * c join_nodes(g, nn(n // 2, n // 2, 'rd'), nn(0, n - 1, 'rd'))
cccr = total_clusters(l_lvl + 3) + 8 * c + 7
# child nodes ^ 4 crossed # grid fill
ccccl = total_clusters(l_lvl + 4) + 16 * c + 5 i = 0
ccccr = total_clusters(l_lvl + 4) + 16 * c + 13 while True:
start = P(n // 2 ** (1 + i) - 1 + n % 2, 0)
step = n // 2 ** (1 + i) - 1 + n % 2
# child nodes ^ 5 crimped if step == 0:
cccccl = total_clusters(l_lvl + 4) + 32 * c + 9 #print(f'Breaking at {i}')
cccccr = total_clusters(l_lvl + 4) + 32 * c + 25 break
# regular set 1 while True:
if l_lvl < n - 1: #for _ in range(2*i+1):
join_nodes(g, nn(i, 'lm'), nn(cl, 'rm')) y = start.y
join_nodes(g, nn(i, 'rm'), nn(cr, 'lm')) 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'))
# irregular: grid ??? start.x += step * 2
if l_lvl < n - 2:
join_nodes(g, nn(i, 'lu'), nn(ccl, 'rd'))
join_nodes(g, nn(i, 'ru'), nn(ccr, 'ld'))
# irregular: grid ????? if start.x + step >= n:
if l_lvl < n - 3: break
join_nodes(g, nn(i, 'ld'), nn(cccl, 'ru'))
join_nodes(g, nn(i, 'rd'), nn(cccr, 'lu'))
# irregulars: inline skips i += 1
#if lvl(i) == lvl(i + l_lvl) and l_lvl: #visualize(g)
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'))
join_nodes(g, nn(i, 'rs'), nn(neigh(i, +l_lvl * 3), 'ls')) # inline skips
join_nodes(g, nn(i, 'ls'), nn(neigh(i, -l_lvl * 5), 'rs')) 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'))
# irregular: inline ring join_nodes(g, nn(x, y, 'lu'), nn(x, (y + n//5) % n, 'lu'))
join_nodes(g, nn(i, 'rs'), nn(neigh(i, +1), 'ls')) join_nodes(g, nn(x, y, 'ru'), nn(x, (y + n//6) % n, 'ru'))
join_nodes(g, nn(i, 'ls'), nn(neigh(i, -1), 'rs'))
#if l_lvl >= 4: join_nodes(g, nn(x, y, 'll'), nn((x + round(n//3)) % n, (y + round(n//3)) % n, 'll'))
#join_nodes(g, nn(i, 'rs'), nn(neigh(i, +12), 'ls'), 6) join_nodes(g, nn(x, y, 'rr'), nn((x + round(n//2)) % n, (y + round(n//2)) % n, 'rr'))
#join_nodes(g, nn(i, 'ls'), nn(neigh(i, -12), 'rs'), 6)
join_nodes(g, nn(x, y, 'lr'), nn((x + round(n//3)) % n, (y - round(n//3)) % n, 'lr'))
join_nodes(g, nn(x, y, 'rl'), nn((x + round(n//2)) % n, (y - round(n//2)) % n, 'rl'))
return g return g
@@ -164,51 +186,58 @@ 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, ps_min = 0, ps_max = False, color = 'black', width = 1.0, debug = False, direct = False): 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 = [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 lvl_max.__class__ == bool: for i in 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)] pa, pb = i
else:
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))]
if ps_max.__class__ == bool: constraints = [True] * 4
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 (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: else:
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))] if all(constraints):
edgelist_filtered.append(i)
#if fmode:
# if all(filt):
# edgelist_filtered.append(i)
#else:
# if any(filt):
# edgelist_filtered.append(i)
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_filtered, width = width, edge_color = color)
else: 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 = { pos = {
'ls': (-2, 0), 'll': (-3, 0),
'lu': (-1, 1), 'lu': (-2, 1),
'ld': (-1, -1), 'lr': (-1, 0),
'lm': (-1, 0), 'ld': (-2, -1),
'm' : (0, 0), 'rl': (1, 0),
'rm': (1, 0), 'ru': (2, 1),
'ru': (1, 1), 'rr': (3, 0),
'rd': (1, -1), 'rd': (2, -1)
'rs': (2, 0)
} }
exp_pos = {} exp_pos = {}
@@ -216,33 +245,27 @@ 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():
from math import log from math import log
bx, by = get_cluster_base_coords(i) bx, by = xy(i)
scaler = (log(nn_total_levels, 2) + 1) * 2 exp_pos[nn(i, j)] = (v[0] + bx * 8, v[1] + by * 3)
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 = 100)
nx.draw_networkx_labels(g, exp_pos, font_size = 8) nx.draw_networkx_labels(g, exp_pos, font_size = 3)
# cluster # cluster
draw_edges_between('', '', lvl_max = 0, ps_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)
# basic tree # regular grid
draw_edges_between('', '', lvl_min = 1, lvl_max = 1, color = '#FF0000', width = 2.0) draw_edges_between('', '', x_min = 1, x_max = 1, y_min = 1, y_max = 1, color = '#FF0000', width = 2.0, fsplit = True)
# inline ring links # anything (debug)
draw_edges_between('ls', 'rs', lvl_max = 0, ps_min = 1, color = '#00FF00', width = 2.0) draw_edges_between('', '', x_min = 1, y_min = 1, color = '#00FF00', width = 2.0, direct = True)
draw_edges_between('lu', 'ld', lvl_max = 0, ps_min = 1, color = '#0000FF', width = 2.0)
draw_edges_between('ru', 'rd', lvl_max = 0, ps_min = 1, color = '#AA00AA', width = 2.0)
# grid links
draw_edges_between('', '', lvl_min = 2, color = '#AAAA00', width = 2.0)
plt.show() plt.show()
def main(): def main():
global write_files global write_files
write_files = True write_files = False
i = 0 i = 0
@@ -259,7 +282,7 @@ def main():
print(r) print(r)
write_file('data.csv', r) write_file('data.csv', r)
if g.number_of_nodes() > 3000: if g.number_of_nodes() > 2000:
break break
def test(): def test():
@@ -276,7 +299,7 @@ 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(9)
visualize(g) visualize(g)
if __name__=="__main__": if __name__=="__main__":