diff --git a/misc/all-graph/04-combine_layout.py b/misc/all-graph/04-combine_layout.py index 80409fd..af6a262 100755 --- a/misc/all-graph/04-combine_layout.py +++ b/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') diff --git a/misc/all-graph/compare.py b/misc/all-graph/compare.py new file mode 100644 index 0000000..33f16be --- /dev/null +++ b/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) diff --git a/misc/graph/build.py b/misc/graph/build.py index ab91d42..58ec8f6 100755 --- a/misc/graph/build.py +++ b/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: diff --git a/misc/graph/combine.py b/misc/graph/combine.py index 4886eb3..886473f 100755 --- a/misc/graph/combine.py +++ b/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}')