Browse Source

update: construction and properties of combined graph

master
Dnomd343 1 week ago
parent
commit
a65696d76c
  1. 50
      misc/all-graph/04-combine_layout.py
  2. 18
      misc/all-graph/compare.py
  3. 2
      misc/graph/combine.py

50
misc/all-graph/04-combine_layout.py

@ -4,30 +4,30 @@ import os
import igraph as ig import igraph as ig
import multiprocessing import multiprocessing
type Union = set[int]
def split_adjacent_layers(graph: ig.Graph, step: int) -> tuple[list[set[int]], list[set[int]]]:
def split_adjacent_layers(graph: ig.Graph, step: int) -> tuple[list[Union], list[Union]]:
layouts = graph.vs.select(step_in=[step, step + 1]) layouts = graph.vs.select(step_in=[step, step + 1])
code_map = {x['code']: x.index for x in layouts} mapping = {x['code']: x.index for x in layouts}
to_index = lambda iter: {code_map[x['code']] for x in iter} spawn_union = lambda iter: {mapping[x['code']] for x in iter}
layer_curr, layer_next = [], [] layer_curr, layer_next = [], []
g_focus = graph.subgraph(layouts) g_focus = graph.subgraph(layouts)
isolated = g_focus.vs.select(_degree=0) if isolated := g_focus.vs.select(_degree=0):
if isolated: assert set(isolated['step']) == {step}
assert {x['step'] for x in isolated} == {step} layer_curr = [spawn_union(isolated)]
layer_curr = [to_index(isolated)]
g_focus.delete_vertices(isolated) g_focus.delete_vertices(isolated)
for component in g_focus.connected_components(): for comp in map(g_focus.vs.select, g_focus.connected_components()):
component = [g_focus.vs[x] for x in component] layer_curr.append(spawn_union(comp.select(step=step)))
layer_curr.append(to_index(x for x in component if x['step'] == step)) layer_next.append(spawn_union(comp.select(step=step+1)))
layer_next.append(to_index(x for x in component if x['step'] == step + 1))
return layer_curr, layer_next return layer_curr, layer_next
def apply_layer_unions(unions_a: list[set[int]], unions_b: list[set[int]]) -> list[set[int]]: def apply_layer_unions(unions_a: list[Union], unions_b: list[Union]) -> list[Union]:
layer_data = {x for u in unions_a for x in u} layouts = {x for u in unions_a for x in u}
assert layer_data == {x for u in unions_b for x in u} assert layouts == {x for u in unions_b for x in u}
unions = [] unions = []
for curr_union in unions_a: for curr_union in unions_a:
@ -40,16 +40,16 @@ def apply_layer_unions(unions_a: list[set[int]], unions_b: list[set[int]]) -> li
assert set(len(x) for x in unions_a) == {0} assert set(len(x) for x in unions_a) == {0}
assert set(len(x) for x in unions_b) == {0} assert set(len(x) for x in unions_b) == {0}
assert layer_data == {x for u in unions for x in u} assert layouts == {x for u in unions for x in u}
return unions return unions
def build_all_unions(graph: ig.Graph) -> list[set[int]]: def build_all_unions(graph: ig.Graph) -> list[Union]:
max_step = max(graph.vs['step']) max_step = max(graph.vs['step'])
layer_unions = [[{x.index for x in graph.vs if x['step'] == 0}]] layer_unions = [[set(graph.vs.select(step=0).indices)]]
for step in range(0, max_step): for step in range(0, max_step):
layer_unions.extend(list(split_adjacent_layers(graph, step))) layer_unions.extend(list(split_adjacent_layers(graph, step)))
layer_unions.append([{x.index for x in graph.vs if x['step'] == max_step}]) layer_unions.append([set(graph.vs.select(step=max_step).indices)])
assert len(layer_unions) == (max_step + 1) * 2 assert len(layer_unions) == (max_step + 1) * 2
all_unions = [] all_unions = []
@ -69,11 +69,11 @@ def combine_graph(graph: ig.Graph) -> ig.Graph:
assert len(combine_idx) == graph.vcount() assert len(combine_idx) == graph.vcount()
assert set(combine_idx) == set(range(len(unions))) assert set(combine_idx) == set(range(len(unions)))
id_len = len(str(len(unions) - 1)) tag_len = len(str(len(unions) - 1))
graph.vs['id'] = [f'U{x:0{id_len}}' for x in combine_idx] graph.vs['tag'] = [f'U{x:0{tag_len}}' for x in combine_idx]
graph.contract_vertices(combine_idx, combine_attrs={'id': 'first', 'step': 'first', 'code': list}) graph.contract_vertices(combine_idx, combine_attrs={'tag': 'first', 'step': 'first', 'code': list})
assert [int(x.removeprefix('U')) for x in graph.vs['id']] == list(range(len(unions))) assert [int(x.removeprefix('U')) for x in graph.vs['tag']] == list(range(len(unions)))
assert not any(x.is_loop() for x in graph.es) assert not any(x.is_loop() for x in graph.es)
graph.simplify(multiple=True) graph.simplify(multiple=True)
return graph return graph
@ -87,14 +87,14 @@ def do_combine(input: str, output: str) -> None:
del graph.vs['code'] del graph.vs['code']
graph.write_pickle(output) # save combined graph graph.write_pickle(output) # save combined graph
g_raw.vs['code'] = g_raw.vs['id'] # modify as origin format g_raw.vs['code'] = g_raw.vs['tag'] # modify as origin format
g_mod = combine_graph(g_raw.copy()) g_mod = combine_graph(g_raw.copy())
assert g_raw.vcount() == g_mod.vcount() assert g_raw.vcount() == g_mod.vcount()
assert g_raw.ecount() == g_mod.ecount() assert g_raw.ecount() == g_mod.ecount()
assert all(x['code'] == [x['id']] for x in g_mod.vs) assert all(x['code'] == [x['tag']] for x in g_mod.vs)
assert g_raw.vs['step'] == g_mod.vs['step'] assert g_raw.vs['step'] == g_mod.vs['step']
assert g_raw.vs['code'] == g_mod.vs['id'] assert g_raw.vs['code'] == g_mod.vs['tag']
assert g_raw.isomorphic(g_mod) assert g_raw.isomorphic(g_mod)

18
misc/all-graph/compare.py

@ -7,18 +7,18 @@ import igraph as ig
def load_legacy(file: str) -> ig.Graph: def load_legacy(file: str) -> ig.Graph:
g = ig.Graph.Read_Pickle(file) g = ig.Graph.Read_Pickle(file)
for node in g.vs: for node in g.vs:
assert sorted(node['code']) == node['code'] node['codes'] = sorted(node['codes'])
node['codes'] = node['code']
del g.vs['code']
return g return g
def load_modern(file: str) -> ig.Graph: def load_modern(file: str) -> ig.Graph:
g = ig.Graph.Read_Pickle(file) g = ig.Graph.Read_Pickle(file)
assert [int(x.removeprefix('U')) for x in g.vs['id']] == list(range(g.vcount()))
for node in g.vs: for idx, node in enumerate(g.vs):
assert sorted(node['codes']) == node['codes'] assert sorted(node['codes']) == node['codes']
del g.vs['id'] assert int(node['tag'].removeprefix('U')) == idx
del g.vs['tag']
return g return g
@ -36,7 +36,9 @@ def compare(g1: ig.Graph, g2: ig.Graph) -> None:
if __name__ == '__main__': if __name__ == '__main__':
for name in sorted(os.listdir('output-combine-raw')): for name in sorted(os.listdir('output-combine')):
g1 = load_legacy(f'output-combine-raw/{name}') if '_' not in name:
continue
g1 = load_legacy(f'combined/{name.split('_')[1]}')
g2 = load_modern(f'output-combine/{name}') g2 = load_modern(f'output-combine/{name}')
compare(g1, g2) compare(g1, g2)

2
misc/graph/combine.py

@ -142,7 +142,7 @@ def export_new_graph(g: ig.Graph, split_data: list[list[set[ig.Vertex]]]) -> ig.
for union_index, nodes in enumerate(unions): for union_index, nodes in enumerate(unions):
index_map[(layer_index, union_index)] = g_index index_map[(layer_index, union_index)] = g_index
ng.vs[g_index]['step'] = layer_index ng.vs[g_index]['step'] = layer_index
ng.vs[g_index]['code'] = [x['code'] for x in nodes] ng.vs[g_index]['codes'] = [x['code'] for x in nodes]
g_index += 1 g_index += 1
for layer_index in range(len(split_data)-1): for layer_index in range(len(split_data)-1):

Loading…
Cancel
Save