diff --git a/main.py b/main.py index f42c8db..446e5b7 100644 --- a/main.py +++ b/main.py @@ -4,45 +4,57 @@ import pandas as pd write_files = False +n = 0 nn_total_levels = 0 -def su(s): - return 2 ** (s + 1) - 1 - -def lvl(i): +def y(i): # backwards compatibility if i.__class__ == str: i = int(i.split('-')[0]) - y = 0 - while i - su(y) >= 0: - y += 1 + return i % round(nn_total_levels ** 0.5) - return y - -def ps(i): +def x(i): # backwards compatibility if i.__class__ == str: i = int(i.split('-')[0]) - y = lvl(i) - return i - su(y-1) + return i // round(nn_total_levels ** 0.5) -def neigh(i, o): - y = lvl(i) - a = 2 ** y - i = i - su(y - 1) - return su(y - 1) + (i + o) % a +def xy(i): + return x(i), y(i) -def nn(cluster_no, node_name): - if not nn_total_levels: - return str(cluster_no) + '-' + node_name - return str(cluster_no % nn_total_levels) + '-' + node_name +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 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) + if g.degree[a] > target_degree or g.degree[b] > target_degree: + g.remove_edge(a, b) + def start_file(p): if not write_files: return @@ -59,12 +71,10 @@ def write_file(p, data): def build_cluster(n): g = nx.Graph() - nodes = ['ls', 'lu', 'lm', 'ld', 'm', 'rs', 'ru', 'rm', 'rd'] - edges = [('ls', 'lu'), ('lu', 'm'), ( 'm', 'ld'), ('ld', 'ls'), - ('ls', 'lm'), ('lu', 'lm'), ( 'm', 'lm'), ('ld', 'lm'), - ('rs', 'ru'), ('ru', 'm'), ( 'm', 'rd'), ('rd', 'rs'), - ('rs', 'rm'), ('ru', 'rm'), ( 'm', 'rm'), ('rd', 'rm'), - ('lu', 'ru'), ('ld', 'rd')] + 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]) @@ -74,73 +84,85 @@ def build_cluster(n): def total_clusters(s): return 2 ** s - 1 -def build_network(n): - throw_dist = 4 +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 = total_clusters(n) + global n, nn_total_levels + n = l_n + nn_total_levels = l_n ** 2 - for i in range(1, nn_total_levels): - c = build_cluster(i) + for j in range(1, nn_total_levels): + c = build_cluster(j) g = nx.union(g, c) - for l_lvl in range(n): - for c in range(2 ** l_lvl): - i = total_clusters(l_lvl) + c + 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')) - # child nodes - cl = total_clusters(l_lvl + 1) + 2 * c - cr = total_clusters(l_lvl + 1) + 2 * c + 1 + 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')) - # child nodes ^ 2 crossed - ccl = total_clusters(l_lvl + 2) + 4 * c + 1 - ccr = total_clusters(l_lvl + 2) + 4 * c + 2 + # 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')) - # child nodes ^ 3 straight - cccl = total_clusters(l_lvl + 3) + 8 * c - cccr = total_clusters(l_lvl + 3) + 8 * c + 7 + 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')) - # child nodes ^ 4 crossed - ccccl = total_clusters(l_lvl + 4) + 16 * c + 5 - ccccr = total_clusters(l_lvl + 4) + 16 * c + 13 + # grid fill + i = 0 + while True: + start = P(n // 2 ** (1 + i) - 1 + n % 2, 0) + step = n // 2 ** (1 + i) - 1 + n % 2 - # child nodes ^ 5 crimped - cccccl = total_clusters(l_lvl + 4) + 32 * c + 9 - cccccr = total_clusters(l_lvl + 4) + 32 * c + 25 + if step == 0: + #print(f'Breaking at {i}') + break - # regular set 1 - if l_lvl < n - 1: - join_nodes(g, nn(i, 'lm'), nn(cl, 'rm')) - join_nodes(g, nn(i, 'rm'), nn(cr, 'lm')) + 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')) - # irregular: grid ??? - if l_lvl < n - 2: - join_nodes(g, nn(i, 'lu'), nn(ccl, 'rd')) - join_nodes(g, nn(i, 'ru'), nn(ccr, 'ld')) + start.x += step * 2 - # 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')) + if start.x + step >= n: + break - # 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')) + i += 1 + #visualize(g) - join_nodes(g, nn(i, 'rs'), nn(neigh(i, +l_lvl * 3), 'ls')) - join_nodes(g, nn(i, 'ls'), nn(neigh(i, -l_lvl * 5), 'rs')) + # 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')) - # irregular: inline ring - join_nodes(g, nn(i, 'rs'), nn(neigh(i, +1), 'ls')) - join_nodes(g, nn(i, 'ls'), nn(neigh(i, -1), 'rs')) + 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')) - #if l_lvl >= 4: - #join_nodes(g, nn(i, 'rs'), nn(neigh(i, +12), 'ls'), 6) - #join_nodes(g, nn(i, 'ls'), nn(neigh(i, -12), 'rs'), 6) + 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')) + + 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 @@ -164,51 +186,58 @@ def analyze(G: nx.Graph) -> dict: '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 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_filtered = [] - if lvl_max.__class__ == bool: - 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)] - 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))] + for i in edgelist: + pa, pb = i - if ps_max.__class__ == bool: - 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)] - 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))] + 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) 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), - 'lm': (-1, 0), - 'm' : (0, 0), - 'rm': (1, 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 = {} @@ -216,33 +245,27 @@ def visualize(g): for i in range(nn_total_levels): for j, v in pos.items(): 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) + 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_nodes(g, exp_pos, node_size = 100) + nx.draw_networkx_labels(g, exp_pos, font_size = 3) # 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 - draw_edges_between('', '', lvl_min = 1, lvl_max = 1, color = '#FF0000', width = 2.0) + # regular grid + 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 - draw_edges_between('ls', 'rs', lvl_max = 0, ps_min = 1, color = '#00FF00', width = 2.0) - 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) + # anything (debug) + draw_edges_between('', '', x_min = 1, y_min = 1, color = '#00FF00', width = 2.0, direct = True) plt.show() def main(): global write_files - write_files = True + write_files = False i = 0 @@ -259,7 +282,7 @@ def main(): print(r) write_file('data.csv', r) - if g.number_of_nodes() > 3000: + if g.number_of_nodes() > 2000: break def test(): @@ -276,7 +299,7 @@ def test2(): print(set([v for i, v in g.degree()])) def test3(): - g = build_network(3) + g = build_network(9) visualize(g) if __name__=="__main__":