华容道高性能计算引擎
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

114 lines
3.7 KiB

#!/usr/bin/env python3
from __future__ import annotations
import os
import re
import igraph as ig
from lxml import etree
from dataclasses import dataclass
class GraphML:
@dataclass(frozen=True)
class Node:
id: str
code: str
step: int
@dataclass(frozen=True)
class Edge:
src: str # node id
dst: str # node id
@dataclass(frozen=True)
class Graph:
name: str
nodes: list[GraphML.Node]
edges: list[GraphML.Edge]
@staticmethod
def __load(name: str, graph: ig.Graph) -> GraphML.Graph:
nodes = []
id_len = len(str(graph.vcount() - 1))
for index in range(graph.vcount()):
info = graph.vs[index]
nodes.append(GraphML.Node(f'n{index:0{id_len}d}', info['code'], info['step']))
edges = []
for n1, n2 in graph.get_edgelist():
node_1 = nodes[n1]
node_2 = nodes[n2]
if node_1.step < node_2.step:
node_1, node_2 = node_2, node_1
edges.append(GraphML.Edge(node_1.id, node_2.id))
return GraphML.Graph(name, nodes, edges)
def __init__(self, *graphs: tuple[str, ig.Graph]):
self.__graphs = [self.__load(*x) for x in graphs]
def __dump_node(self, node: Node) -> etree.Element:
node_xml = etree.Element('node', id=node.id)
etree.SubElement(node_xml, 'data', key='v_code').text = node.code
etree.SubElement(node_xml, 'data', key='v_step').text = str(node.step)
return node_xml
def __dump_edge(self, edge: Edge) -> etree.Element:
return etree.Element('edge', source=edge.src, target=edge.dst)
def __dump_graph(self, graph: Graph) -> etree.Element:
graph_xml = etree.Element('graph', id=graph.name, edgedefault='undirected')
for node in graph.nodes:
graph_xml.append(self.__dump_node(node))
for edge in graph.edges:
graph_xml.append(self.__dump_edge(edge))
return graph_xml
def save_graph(self, output: str) -> None:
graphml = etree.Element('graphml', nsmap={
None: 'http://graphml.graphdrawing.org/xmlns',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
})
graphml.set(
'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation',
'http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd'
)
etree.SubElement(graphml, 'key', attrib={
'id': 'v_code',
'for': 'node',
'attr.name': 'code',
'attr.type': 'string'
})
etree.SubElement(graphml, 'key', attrib={
'id': 'v_step',
'for': 'node',
'attr.name': 'step',
'attr.type': 'int'
})
for graph in self.__graphs:
graphml.append(self.__dump_graph(graph))
xml_tree = etree.ElementTree(graphml)
xml_tree.write(output, pretty_print=True, xml_declaration=True, encoding='utf-8')
def to_graphml(inputs: list[tuple[str, str]], output: str) -> None:
print(f'Convert into {output}')
gml = GraphML(*((x, ig.Graph.Read_Pickle(y)) for x, y in inputs))
gml.save_graph(output)
def convert_graphs(input_dir: str, output_dir: str) -> None:
files = [x.removesuffix('.pkl') for x in os.listdir(input_dir) if x.endswith('.pkl')]
tags = sorted(x for x in files if re.match(r'^\d\-\d\d(L|R|M)$', x))
for tag in tags:
output_file = os.path.join(output_dir, f'{tag}.graphml')
pkls = sorted(x for x in files if x.startswith(tag))
to_graphml([(x, os.path.join(input_dir, f'{x}.pkl')) for x in pkls], output_file)
if __name__ == "__main__":
os.makedirs('output-gml', exist_ok=True)
convert_graphs('output-ig', 'output-gml')