Browse Source

update: optimize and verify combine algorithm

master
Dnomd343 1 week ago
parent
commit
29f66f18fe
  1. 43
      misc/all-graph/04-combine_layout.py
  2. 40
      misc/all-graph/compare.py
  3. 4
      misc/graph/build.py
  4. 38
      misc/graph/combine.py

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

@ -1,6 +1,8 @@
#!/usr/bin/env python3
import os
import igraph as ig
import multiprocessing
def split_layer(graph: ig.Graph, step_a: int, step_b: int) -> tuple[list[set[int]], list[set[int]]]:
@ -37,13 +39,18 @@ def split_layer(graph: ig.Graph, step_a: int, step_b: int) -> tuple[list[set[int
data_a: list[set[int]] = []
data_b: list[set[int]] = []
special_set = set()
while layer_a:
# TODO: maybe we should combine all union_a when union_b is empty
union_a, union_b = extend_from(layer_a.pop())
if len(union_b) == 0:
assert len(union_a) == 1
special_set.update(union_a)
continue
layer_a -= union_a
layer_b -= union_b
data_a.append(set(x.index for x in union_a))
data_b.append(set(x.index for x in union_b))
data_a.append(set(x.index for x in special_set))
assert len(layer_a) == 0 and len(layer_b) == 0
assert sum(len(x) for x in data_a) == layer_num_a
@ -69,8 +76,7 @@ def build_multi_set(unions_a: list[set[int]], unions_b: list[set[int]]) -> list[
return release
def do_split(file: str) -> ig.Graph:
g = ig.Graph.Read_Pickle(file)
def do_split(g: ig.Graph) -> ig.Graph:
max_step = max(x['step'] for x in g.vs)
layer_data = [[] for _ in range(max_step + 1)]
@ -108,6 +114,33 @@ def do_split(file: str) -> ig.Graph:
return g
def do_combine(input: str, output: str) -> None:
print(f'Start combining: {input}')
g = do_split(ig.Graph.Read_Pickle(input))
g.write_pickle(output)
g_mod = g.copy()
for x in g_mod.vs:
x['code'] = '+'.join(x['code'])
g_mod = do_split(g_mod)
assert g.vcount() == g_mod.vcount()
assert g.ecount() == g_mod.ecount()
for index in range(g.vcount()):
assert len(g_mod.vs[index]['code']) == 1
assert g.vs[index]['step'] == g_mod.vs[index]['step']
assert '+'.join(g.vs[index]['code']) == g_mod.vs[index]['code'][0]
assert g.isomorphic(g_mod)
def combine_all(ig_dir: str, output_dir: str) -> None:
pool = multiprocessing.Pool()
for name in sorted(os.listdir(ig_dir)):
pool.apply_async(do_combine, args=(f'{ig_dir}/{name}', f'{output_dir}/{name}'))
pool.close()
pool.join()
if __name__ == "__main__":
g_release = do_split('output-ig/1-00M-000Y_DAA7F30.pkl')
g_release.write_pickle('1-00M-000Y_DAA7F30-combined.pkl')
os.makedirs('output-combine', exist_ok=True)
combine_all('output-ig', 'output-combine')

40
misc/all-graph/compare.py

@ -0,0 +1,40 @@
#!/usr/bin/env python3
import os
import igraph as ig
def load_legacy(file: str) -> ig.Graph:
g = ig.Graph.Read_Pickle(file)
for node in g.vs:
node['code'] = sorted(node['code'])
return g
def load_modern(file: str) -> ig.Graph:
g = ig.Graph.Read_Pickle(file)
for node in g.vs:
assert sorted(node['code']) == sorted(node['code'])
return g
def compare(g1: ig.Graph, g2: ig.Graph) -> None:
assert g1.vcount() == g2.vcount()
assert g1.ecount() == g2.ecount()
assert g1.isomorphic(g2)
assert {len(x.attributes()) for x in g1.es} == {0}
assert {len(x.attributes()) for x in g2.es} == {0}
data_a = {min(x['code']): x.attributes() for x in g1.vs}
data_b = {min(x['code']): x.attributes() for x in g2.vs}
assert data_a == data_b
if __name__ == '__main__':
for name in sorted(os.listdir('output-combine')):
if '_' not in name:
continue
g1 = load_legacy(f'combined/{name.split('_')[1]}')
g2 = load_modern(f'output-combine/{name}')
compare(g1, g2)

4
misc/graph/build.py

@ -32,10 +32,10 @@ def build_step_map(code: str) -> dict[Layout, int]:
def build_min_step_scope(group: Group, targets: list[str]) -> dict[Layout, dict[Layout, int]]:
targets = [Layout(x) for x in targets]
all_solution = set([x for x in group.cases() if str(x).startswith('D')])
all_solution = set([x for x in list(group.cases()) if str(x).startswith('D')])
not_solved = all_solution - set(targets)
step_data = {x: {} for x in group.cases() if x not in not_solved}
step_data = {x: {} for x in list(group.cases()) if x not in not_solved}
for target in targets:
for code, step_num in build_step_map(target).items():
if code in not_solved:

38
misc/graph/combine.py

@ -1,5 +1,6 @@
#!/usr/bin/env python3
import os
import igraph as ig
@ -13,6 +14,15 @@ def split_neighbor_layer(g: ig.Graph, n: int) -> tuple[list[set[ig.Vertex]], lis
select_next = lambda p: set(x for x in p.neighbors() if x['step'] == n + 1)
select_last = lambda p: set(x for x in p.neighbors() if x['step'] == n)
layer_a_data.append(set())
for node in layer_a:
if not select_next(node):
layer_a_data[0].add(node)
for node in layer_a_data[0]:
layer_a.remove(node)
if not layer_a_data[0]:
layer_a_data.clear()
while len(layer_a) != 0:
side_a: set[ig.Vertex] = set()
side_b: set[ig.Vertex] = set()
@ -91,7 +101,7 @@ def combine_split_result(data_a: list[set[ig.Vertex]], data_b: list[set[ig.Verte
def split_layers(g: ig.Graph) -> list[list[set[ig.Vertex]]]:
assert min(g.vs['step']) == 0
layer_num = max(g.vs['step']) + 1
print(f'layer_num: {layer_num}')
# print(f'layer_num: {layer_num}')
layers = [{'up': [], 'down': []} for x in range(layer_num)]
layers[0]['up'] = [set(g.vs.select(step=0))]
@ -132,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):
index_map[(layer_index, union_index)] = g_index
ng.vs[g_index]['step'] = layer_index
ng.vs[g_index]['codes'] = [x['code'] for x in nodes]
ng.vs[g_index]['code'] = [x['code'] for x in nodes]
g_index += 1
for layer_index in range(len(split_data)-1):
@ -157,14 +167,20 @@ def export_new_graph(g: ig.Graph, split_data: list[list[set[ig.Vertex]]]) -> ig.
return ng
if __name__ == '__main__':
raw = ig.Graph.Read_Pickle('data/DAA7F30.pkl')
# raw = ig.Graph.Read_Pickle('data/DBAB4CC.pkl')
# raw = ig.Graph.Read_Pickle('main_combined.pkl')
print(raw.summary())
def do_combine(input: str, output: str):
print(f'Combine {input} -> {output}')
raw = ig.Graph.Read_Pickle(input)
gg = export_new_graph(raw, split_layers(raw))
print(gg.summary())
# print(gg.isomorphic(raw))
# print(raw.summary())
# print(gg.summary())
# print(raw.isomorphic(gg))
gg.write_pickle(output)
if __name__ == '__main__':
do_combine('data/DAA7F30.pkl', 'main_combined.pkl')
# do_combine('data/DBAB4CC.pkl', 'main_combined.pkl')
# do_combine('main_combined.pkl', 'main_combined.pkl')
gg.write_pickle('main_combined.pkl')
# gg.write_graphml('main_combined.graphml')
# for name in os.listdir('data'):
# do_combine(f'data/{name}', f'{name}')

Loading…
Cancel
Save