Skip to content

Commit fbfbf75

Browse files
committed
fix: Parser no longer (implictly) assumed ordered inputs/outputs.
1 parent 5af12f9 commit fbfbf75

File tree

3 files changed

+132
-87
lines changed

3 files changed

+132
-87
lines changed

aiger/parser.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __repr__(self):
2727
f"{self.num_latches} {self.num_outputs} {self.num_ands}"
2828

2929

30-
NOT_DONE_PARSING_ERROR = "Lines exhausted before parsing ended!\n{}"
30+
NOT_DONE_PARSING_ERROR = "Parsing rules exhausted at line {}!\n{}"
3131
DONE_PARSING_ERROR = "Lines exhausted before parsing ended!\n{}"
3232

3333

@@ -59,9 +59,9 @@ class SymbolTable:
5959
@attr.s(auto_attribs=True)
6060
class State:
6161
header: Optional[Header] = None
62-
inputs: SortedSet = attr.ib(factory=SortedSet)
63-
outputs: list = attr.ib(factory=list)
64-
latches: SortedSet = attr.ib(factory=SortedSet)
62+
inputs: List[str] = attr.ib(factory=list)
63+
outputs: List[str] = attr.ib(factory=list)
64+
latches: List[str] = attr.ib(factory=list)
6565
symbols: SymbolTable = attr.ib(factory=SymbolTable)
6666
comments: Optional[List[str]] = None
6767
nodes: SortedDict = attr.ib(factory=SortedDict)
@@ -113,15 +113,16 @@ def parse_header(state, line) -> bool:
113113
return True
114114

115115

116-
IO_PATTERN = re.compile(r"(\d+)\n")
116+
IO_PATTERN = re.compile(r"(\d+)\s*\n")
117117

118118

119119
def parse_input(state, line) -> bool:
120120
match = IO_PATTERN.match(line)
121+
121122
if match is None or state.remaining_inputs <= 0:
122123
return False
123124
lit = int(line)
124-
state.inputs.add(lit)
125+
state.inputs.append(lit)
125126
state.nodes[lit] = set()
126127
return True
127128

@@ -153,15 +154,15 @@ def parse_latch(state, line) -> bool:
153154
elems = elems[:2] + (0,)
154155
elems = fn.lmap(int, elems)
155156

156-
state.latches.add(Latch(*elems))
157+
state.latches.append(Latch(*elems))
157158
state.nodes[elems[0]] = set() # Add latch in as source.
158159
lit = elems[1] # Add latchout to dependency graph.
159160
if lit & 1:
160161
state.nodes[lit] = {lit ^ 1}
161162
return True
162163

163164

164-
AND_PATTERN = re.compile(r"(\d+) (\d+) (\d+)\n")
165+
AND_PATTERN = re.compile(r"(\d+) (\d+) (\d+)\s*\n")
165166

166167

167168
def parse_and(state, line) -> bool:
@@ -182,7 +183,7 @@ def parse_and(state, line) -> bool:
182183
return True
183184

184185

185-
SYM_PATTERN = re.compile(r"([ilo])(\d+) (.*)\n")
186+
SYM_PATTERN = re.compile(r"([ilo])(\d+) (.*)\s*\n")
186187

187188

188189
def parse_symbol(state, line) -> bool:
@@ -234,12 +235,12 @@ def parse(lines, to_aig: bool = True):
234235
parsers = parse_seq()
235236
parser = next(parsers)
236237

237-
for line in lines:
238+
for i, line in enumerate(lines):
238239
while not parser(state, line):
239240
parser = next(parsers, None)
240241

241242
if parser is None:
242-
raise ValueError(NOT_DONE_PARSING_ERROR.format(state))
243+
raise ValueError(NOT_DONE_PARSING_ERROR.format(i + 1, state))
243244

244245
if parser not in (parse_header, parse_output, parse_comment, parse_symbol):
245246
raise ValueError(DONE_PARSING_ERROR.format(state))
@@ -249,6 +250,9 @@ def parse(lines, to_aig: bool = True):
249250
assert state.remaining_outputs == 0
250251
assert state.remaining_latches == 0
251252

253+
if len(state.inputs) != len(set(state.inputs)):
254+
raise ValueError("Duplicated inputs detected.")
255+
252256
# Complete Symbol Table.
253257
inputs = bidict(finish_table(state.symbols.inputs, state.inputs))
254258
outputs = finish_table(state.symbols.outputs, state.outputs)

0 commit comments

Comments
 (0)