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
nn_total_levels = 0
2026-09-30 14:30:08 +03:00
def nn ( cluster_no , node_name ):
2026-09-30 20:56:36 +03:00
if not nn_total_levels :
return str ( cluster_no ) + '-' + node_name
return str ( cluster_no % nn_total_levels ) + '-' + node_name
2026-10-01 22:17:45 +03:00
def lvl ( node_name ):
return int ( node_name . split ( '-' )[ 0 ])
def join_nodes ( g , a , b , target_degree = 6 ):
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 )
def start_file ( p ):
index = [ 'i' , 'N' , 'E' , 'S' , 'D' , 'D_avg' , 'T' , 'C' ]
open ( p , 'w' ) . write ( ',' . join ( index ) + ' \n ' )
def write_file ( p , data ):
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 ()
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' )]
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-09-30 20:56:36 +03:00
def build_network ( n ):
2026-09-30 19:00:53 +03:00
throw_dist = 4
2026-09-30 20:56:36 +03:00
g = build_cluster ( 0 )
global nn_total_levels
nn_total_levels = n
for i in range ( 1 , n ):
2026-09-30 14:30:08 +03:00
c = build_cluster ( i )
g = nx . union ( g , c )
2026-09-30 20:56:36 +03:00
for i in range ( n ):
if n >= 2 :
if i % 2 :
2026-10-01 22:17:45 +03:00
join_nodes ( g , nn ( i , 'lu' ), nn ( i - 1 , 'lu' ), 4 )
join_nodes ( g , nn ( i , 'rd' ), nn ( i - 1 , 'rd' ), 4 )
2026-09-30 20:56:36 +03:00
else :
2026-10-01 22:17:45 +03:00
join_nodes ( g , nn ( i , 'ld' ), nn ( i - 1 , 'ld' ), 4 )
join_nodes ( g , nn ( i , 'ru' ), nn ( i - 1 , 'ru' ), 4 )
2026-09-30 14:30:08 +03:00
2026-09-30 20:56:36 +03:00
g . add_edge ( nn ( i , 'ls' ), nn ( i - 1 , 'rs' ))
g . add_edge ( nn ( i , 'rs' ), nn ( i - 1 , 'ls' ))
2026-09-30 19:00:53 +03:00
2026-10-01 22:17:45 +03:00
if n > 1 * throw_dist :
2026-09-30 19:00:53 +03:00
g . add_edge ( nn ( i , 'rs' ), nn ( i - ( 1 * throw_dist ), 'ls' ))
g . add_edge ( nn ( i , 'ls' ), nn ( i - ( 1 * throw_dist ), 'rs' ))
2026-09-30 20:56:36 +03:00
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 )
2026-09-30 19:00:53 +03: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-01 22:17:45 +03:00
def visualize ( g ):
def draw_edges_between ( a , b , lvl_min = 0 , lvl_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 ])]
if debug :
print ( edgelist )
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 )]
'''
for p in edgelist:
if abs(lvl(pa) - lvl(pb)) < lvl_min:
edgelist.remove((pa, pb))
'''
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 ))]
'''
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 direct :
nx . draw_networkx_edges ( g , exp_pos , edgelist = edgelist , 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 )
pos = {
'ls' : ( - 2 , 0 ),
'lu' : ( - 1 , 1 ),
'ld' : ( - 1 , - 1 ),
'm' : ( 0 , 0 ),
'ru' : ( 1 , 1 ),
'rd' : ( 1 , - 1 ),
'rs' : ( 2 , 0 )
}
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 )
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)
# cluster
draw_edges_between ( '' , '' , lvl_max = 0 , color = '#888888' , width = 0.5 , direct = True )
# S => 4
draw_edges_between ( 'ls' , 'rs' , lvl_max = 1 , color = '#33AAAA' , width = 2 )
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 )
# 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 )
plt . show ()
2026-09-30 14:30:08 +03:00
def main ():
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 })
'''
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 :
break
2026-09-30 14:30:08 +03:00
2026-09-30 19:00:53 +03:00
#print(r)
2026-09-30 20:56:36 +03:00
#nx.draw(g, with_labels = True)
#plt.show()
#d.to_csv('data.csv')
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 ():
g = build_network ( 3 )
#print(g.adj['0-ls'])
visualize ( g )
2026-09-30 14:30:08 +03:00
if __name__ == "__main__" :
2026-10-01 22:17:45 +03:00
test3 ()