mirror of https://github.com/dnomd343/klotski.git
Dnomd343
6 days ago
1 changed files with 176 additions and 0 deletions
@ -0,0 +1,176 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
|
||||
|
import igraph as ig |
||||
|
|
||||
|
|
||||
|
def split_neighbor_layer(g: ig.Graph, n: int) -> tuple[list[set[ig.Vertex]], list[set[ig.Vertex]]]: |
||||
|
layer_a: set[ig.Vertex] = set(g.vs.select(step=n)) |
||||
|
layer_b: set[ig.Vertex] = set(g.vs.select(step=n+1)) |
||||
|
|
||||
|
layer_a_data: list[set[ig.Vertex]] = [] |
||||
|
layer_b_data: list[set[ig.Vertex]] = [] |
||||
|
|
||||
|
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) |
||||
|
|
||||
|
while len(layer_a) != 0: |
||||
|
side_a: set[ig.Vertex] = set() |
||||
|
side_b: set[ig.Vertex] = set() |
||||
|
|
||||
|
point = layer_a.pop() |
||||
|
side_a.add(point) |
||||
|
|
||||
|
while True: |
||||
|
nexts = set() |
||||
|
for x in side_a: |
||||
|
nexts.update(select_next(x)) |
||||
|
if nexts == side_b: |
||||
|
break |
||||
|
side_b.update(nexts) |
||||
|
for x in nexts: |
||||
|
if x in layer_b: |
||||
|
layer_b.remove(x) |
||||
|
|
||||
|
lasts = set() |
||||
|
for x in side_b: |
||||
|
lasts.update(select_last(x)) |
||||
|
if lasts == side_a: |
||||
|
break |
||||
|
side_a.update(lasts) |
||||
|
for x in lasts: |
||||
|
if x in layer_a: |
||||
|
layer_a.remove(x) |
||||
|
|
||||
|
layer_a_data.append(side_a) |
||||
|
layer_b_data.append(side_b) |
||||
|
|
||||
|
assert len(layer_b) == 0 |
||||
|
return layer_a_data, layer_b_data |
||||
|
|
||||
|
|
||||
|
def combine_split_result(data_a: list[set[ig.Vertex]], data_b: list[set[ig.Vertex]]) -> list[set[ig.Vertex]]: |
||||
|
result = [] |
||||
|
|
||||
|
while True: |
||||
|
data_a = list(filter(None, data_a)) |
||||
|
data_b = list(filter(None, data_b)) |
||||
|
data_a = sorted(data_a, key=lambda x: len(x)) |
||||
|
data_b = sorted(data_b, key=lambda x: len(x)) |
||||
|
|
||||
|
if len(data_a) == 0: |
||||
|
assert len(data_b) == 0 |
||||
|
break |
||||
|
|
||||
|
# print(len(data_a)) |
||||
|
# for x in data_a: |
||||
|
# print([y.attributes() for y in x]) |
||||
|
# print(len(data_b)) |
||||
|
# for x in data_b: |
||||
|
# print([y.attributes() for y in x]) |
||||
|
# print('-' * 64) |
||||
|
|
||||
|
if len(data_a[0]) <= len(data_b[0]): |
||||
|
union = data_a[0] |
||||
|
peer_unions = data_b |
||||
|
else: |
||||
|
union = data_b[0] |
||||
|
peer_unions = data_a |
||||
|
|
||||
|
for peer_union in peer_unions: |
||||
|
mid = union & peer_union |
||||
|
if len(mid) == 0: |
||||
|
continue |
||||
|
result.append(mid) |
||||
|
for x in mid: |
||||
|
union.remove(x) |
||||
|
peer_union.remove(x) |
||||
|
|
||||
|
return result |
||||
|
|
||||
|
|
||||
|
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(layer_num) |
||||
|
|
||||
|
layers = [{'up': [], 'down': []} for x in range(layer_num)] |
||||
|
layers[0]['up'] = [set(g.vs.select(step=0))] |
||||
|
layers[-1]['down'] = [set(g.vs.select(step=layer_num-1))] |
||||
|
|
||||
|
for layer_num in range(layer_num - 1): |
||||
|
data_a, data_b = split_neighbor_layer(g, layer_num) |
||||
|
layers[layer_num]['down'] = data_a |
||||
|
layers[layer_num + 1]['up'] = list(filter(None, data_b)) |
||||
|
|
||||
|
for layer in layers: |
||||
|
assert set() not in layer['up'] |
||||
|
assert set() not in layer['down'] |
||||
|
up = set() |
||||
|
[up.update(x) for x in layer['up']] |
||||
|
down = set() |
||||
|
[down.update(x) for x in layer['down']] |
||||
|
assert up == down |
||||
|
|
||||
|
result = [] |
||||
|
for layer in layers: |
||||
|
result.append(combine_split_result(layer['up'], layer['down'])) |
||||
|
|
||||
|
for layer_num, layer in enumerate(result): |
||||
|
assert set() not in layer |
||||
|
layer_nodes = set() |
||||
|
[layer_nodes.update(x) for x in layer] |
||||
|
assert layer_nodes == set(g.vs.select(step=layer_num)) |
||||
|
return result |
||||
|
|
||||
|
|
||||
|
def export_new_graph(g: ig.Graph, split_data: list[list[set[ig.Vertex]]]) -> ig.Graph: |
||||
|
ng = ig.Graph(sum([len(x) for x in split_data])) |
||||
|
|
||||
|
g_index = 0 |
||||
|
index_map = {} |
||||
|
for layer_index, unions in enumerate(split_data): |
||||
|
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] |
||||
|
g_index += 1 |
||||
|
|
||||
|
for layer_index in range(len(split_data)-1): |
||||
|
curr_layer = split_data[layer_index] |
||||
|
next_layer = split_data[layer_index+1] |
||||
|
|
||||
|
def union_neighbors(curr_union_index: int) -> list[int]: |
||||
|
next_union_indexes = set() |
||||
|
for node in curr_layer[curr_union_index]: |
||||
|
next_nodes = [x for x in node.neighbors() if x['step'] == layer_index+1] |
||||
|
for next_node in next_nodes: |
||||
|
for next_union_index in range(len(next_layer)): |
||||
|
if next_node in next_layer[next_union_index]: |
||||
|
next_union_indexes.add(next_union_index) |
||||
|
return sorted(next_union_indexes) |
||||
|
|
||||
|
for union_index in range(len(curr_layer)): |
||||
|
union_a = index_map[(layer_index, union_index)] |
||||
|
edges = [(union_a, index_map[(layer_index+1, x)]) for x in union_neighbors(union_index)] |
||||
|
ng.add_edges(edges) |
||||
|
|
||||
|
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()) |
||||
|
gg = export_new_graph(raw, split_layers(raw)) |
||||
|
print(gg.summary()) |
||||
|
# print(gg.isomorphic(raw)) |
||||
|
|
||||
|
# for x in gg.vs: |
||||
|
# x['color'] = 'yellow' |
||||
|
# gg.vs[0]['color'] = 'red' |
||||
|
# print(gg) |
||||
|
# ig.plot(gg, 'demo.png', vertex_size=10) |
||||
|
|
||||
|
# gg.write_pickle('main_combined.pkl') |
||||
|
# gg.write_graphml('main_combined.graphml') |
Loading…
Reference in new issue