-
Notifications
You must be signed in to change notification settings - Fork 0
/
io_parser.py
135 lines (110 loc) · 4.41 KB
/
io_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import os
import pickle
import re
from pathlib import Path
from models import Graph
class AbstractIO:
input_directory = 'instances'
output_directory = 'output'
test_directory = 'tests/instances'
default_filename = 'test'
def read(self, name):
raise NotImplementedError
def write(self, graph, file_name=None):
raise NotImplementedError
def _read_from_file(self, file_name, is_test=False):
directory = self.test_directory if is_test else self.input_directory
file_path = os.path.join(os.getcwd(), directory, file_name)
return Path(file_path).read_text()
def _write_to_file(self, string, file_name, output_directory=None):
if not output_directory:
output_directory = self.output_directory
self._ensure_output_directory()
file_path = os.path.join(os.getcwd(), output_directory, file_name)
Path(file_path).write_text(string)
def _ensure_output_directory(self):
directory = os.path.join(os.getcwd(), self.output_directory)
if not os.path.exists(directory):
os.makedirs(directory)
class DotParser(AbstractIO):
def read(self, file_name, is_test=False):
graph = Graph()
string = self._read_from_file(file_name, is_test)
string = string.replace(';', '')
tokens = string.split()
vertex_1 = vertex_2 = edge = None
for token in tokens:
if token.isdigit():
if not vertex_1:
vertex_1 = token
else:
vertex_2 = token
elif token == '--':
edge = token
if vertex_1 and vertex_2 and edge:
graph.add_edge(vertex_1, vertex_2)
vertex_1 = vertex_2 = edge = None
return graph
def write(self, graph, file_name=None, output_directory=None):
string = 'graph {\n'
for edge in graph.edges:
string += ' %s -- %s;\n' % (edge[0], edge[1])
string += '}'
if not file_name:
file_name = self.default_filename + '.dot'
self._write_to_file(string, file_name, output_directory)
class PickleParser(AbstractIO):
def read(self, file_name):
self._ensure_output_directory()
with open(self.output_directory + '/' + file_name, mode='rb')\
as binary_file:
return pickle.load(binary_file)
def write(self, obj, file_name=None):
if not file_name:
file_name = self.default_filename + '.bin'
self._ensure_output_directory()
with open(self.output_directory + '/' + file_name, mode='wb')\
as binary_file:
pickle.dump(obj, binary_file)
class ASCIIParser(AbstractIO):
"""
Parse graphs that are created with Plantri
"""
def read(self, file, number=1):
with open(file, 'r', encoding='latin1') as f:
for i, line in enumerate(f.readlines(), 1):
if i == number:
return self._parse(line)
def read_all(self, file):
with open(file, 'r', encoding='latin1') as f:
for i, line in enumerate(f.readlines(), 1):
yield self._parse(line)
def _parse(self, line):
graph = Graph()
line = line.split(' ')[1].replace('\n', '') # remove number of vertices
vertices = line.split(',')
current_vertex = ord('a') - 96 # a == 97
for vertex in vertices:
neighbors = []
for neighbor_vertex in vertex:
neighbor = ord(neighbor_vertex) - 96
neighbors.append(neighbor)
graph.add_edge(current_vertex, neighbor)
graph.add_circular_edge_order(current_vertex, neighbors) # counterclockwise order of neighbours. in the ascii file it is clockwise
current_vertex += 1
return graph
class GraphML(AbstractIO):
def read(self, file):
graph = Graph()
with open(file, 'r') as f:
# Quick way to parse the rome graphs
for line in f.readlines():
if line.startswith('<node'):
v = re.search(r'"(.+)"', line).group(1)
graph.add_vertex(v)
elif line.startswith('<edge'):
res = re.findall(r'"(.+?)"', line)
v1 = res[1] # [0} is the edge id
v2 = res[2]
graph.add_edge(v1, v2)
return graph