+ # Reverse an automaton in place
+ fun reverse
+ do
+ for s in states do
+ var tmp = s.ins
+ s.ins = s.outs
+ s.outs = tmp
+ for t in s.outs do
+ var tmp2 = t.from
+ t.from = t.to
+ t.to = tmp2
+ end
+ end
+ var st = start
+ if accept.length == 1 then
+ start = accept.first
+ else
+ var st2 = new State
+ start = st2
+ states.add(st2)
+
+ for s in accept do
+ st2.add_trans(s, null)
+ end
+ end
+ accept.clear
+ accept.add(st)
+ end
+
+ # Remove states (and transitions) that does not reach an accept state
+ fun trim
+ do
+ # Good states are those we want to keep
+ var goods = new HashSet[State]
+ goods.add_all(accept)
+
+ var todo = accept.to_a
+
+ # Propagate goodness
+ while not todo.is_empty do
+ var s = todo.pop
+ for t in s.ins do
+ var s2 = t.from
+ if goods.has(s2) then continue
+ goods.add(s2)
+ todo.add(s2)
+ end
+ end
+
+ # What are the bad state then?
+ var bads = new Array[State]
+ for s in states do
+ if not goods.has(s) then bads.add(s)
+ end
+
+ # Remove their transitions
+ for s in bads do
+ for t in s.ins do t.delete
+ for t in s.outs do t.delete
+ end
+
+ # Keep only the good stuff
+ states.clear
+ states.add_all(goods)
+ end
+
+ # Generate a minimal DFA
+ # REQUIRE: self is a DFA
+ fun to_minimal_dfa: Automaton
+ do
+ trim
+
+ var distincts = new HashMap[State, Set[State]]
+ for s in states do
+ distincts[s] = new HashSet[State]
+ end
+
+ # split accept states
+ for s1 in states do
+ for s2 in states do
+ if distincts[s1].has(s2) then continue
+ if not accept.has(s1) then continue
+ if not accept.has(s2) then
+ distincts[s1].add(s2)
+ distincts[s2].add(s1)
+ continue
+ end
+ if tags[s1] != tags[s2] then
+ distincts[s1].add(s2)
+ distincts[s2].add(s1)
+ continue
+ end
+ end
+ end
+
+ var changed = true
+ var ints = new Array[Int]
+ while changed do
+ changed = false
+ for s1 in states do for s2 in states do
+ if distincts[s1].has(s2) then continue
+ ints.clear
+ for t in s1.outs do
+ var sym = t.symbol
+ assert sym != null
+ ints.add sym.first
+ var l = sym.last
+ if l != null then ints.add l
+ end
+ for i in ints do
+ var ds1 = s1.trans(i)
+ var ds2 = s2.trans(i)
+ if ds1 == null and ds2 == null then continue
+ if ds1 != null and ds2 != null and not distincts[ds1].has(ds2) then continue
+ distincts[s1].add(s2)
+ distincts[s2].add(s1)
+ changed = true
+ break
+ end
+ end
+ end
+
+ for s1 in states do for s2 in states do
+ if distincts[s1].has(s2) then continue
+ s1.add_trans(s2, null)
+ end
+
+ return to_dfa
+ end
+