Mini Shell
class FiniteAutomaton:
def __init__(self, start_state, dump_state=''):
self.start_state = start_state
self.dump_state = dump_state
self.table = {self.dump_state: {}}
self.unresolved_composites = []
self.resolved_composites = []
self.composite_memo = {}
self.is_updated = 1
def __setitem__(self, xxx_todo_changeme, x):
(state, symbol) = xxx_todo_changeme
self.table.setdefault(state, {})[symbol] = x
self.is_updated = 1
def add_transition(self, state, symbol, *nexts):
if len(nexts) == 1:
c = nexts[0]
else:
for n in nexts:
if n not in self.table:
self.table[n] = {}
c = self.new_composite(nexts)
self[state, symbol] = c
if c not in self.table:
self.table[c] = {}
def get_row_items(self, state):
try:
x = list(self.table[state].items())
except KeyError:
return ()
ris = []
for k, v in x:
if isinstance(v, CompositeState):
for vi in v:
ris.append((k, vi))
else:
ris.append((k, v))
return ris
def make_deterministic(self):
# Resolve all unresolved composite states so we become deterministic
while self.unresolved_composites:
composites = self.unresolved_composites
self.unresolved_composites = []
for c in composites:
ds = {}
l = []
for a in c:
for k, v in self.get_row_items(a):
ds.setdefault(k, []).append(v)
for k, v in list(ds.items()):
for a in c:
if k not in self.table[a]:
v.append(self.dump_state)
break
for k, v in list(ds.items()):
self.add_transition(c, k, *v)
def get_all_input_symbols(self):
syms = {}
for state, trans in list(self.table.items()):
for k, v in trans:
syms[k] = 1
return syms
def get_all_states(self):
return self.table
def get_all_final_states(self):
return {}
def get_composites(self):
if self.is_updated:
self.make_deterministic()
return list(self.composite_memo.values())
def get_transition_classes(self):
# Get classes of states that have the same outgoing transitions
tc = {}
tck = {}
for k, v in list(self.table.items()):
trans = list(v.keys())
trans.sort()
trans = tuple(trans)
ks = tc.get(trans)
if ks is None:
ks = []
tc[trans] = ks
ks.append(k)
tck[k] = ks
return tc, tck
def get_minimized_dfa(self, finals):
def markall(finals, tcv, table):
def psrmark(l):
for pq in l:
if pq in PS:
l1 = PS[pq]
del PS[pq]
if l1:
psrmark(l1)
PS = {}
for Q in tcv:
for ip, p in enumerate(Q):
for q in Q[ip+1:]:
if (p in finals) == (q in finals):
PS[(p, q)] = ()
for pq in list(PS.keys()):
p, q = pq
dp = table[p]
dq = table[q]
# Now we know they contain the same symbols
dps = []
for a in dp:
dpa = dp[a]
dqa = dq[a]
if dpa is not dqa:
dpadqa = (dpa, dqa)
if dpadqa in PS:
dps.append(dpadqa)
else:
dqadpa = (dqa, dpa)
if dqadpa in PS:
dps.append(dqadpa)
else:
l = PS[pq]
del PS[pq]
if l is not ():
psrmark(l)
break
else:
for dpadqa in dps:
l = PS[dpadqa]
if l is ():
l = [pq]
PS[dpadqa] = l
else:
l.append(pq)
return PS
def combine(QS, PQS):
eqs = {}
for Q in QS:
for p in Q:
eqs[p] = [p]
for p, q in PQS:
#
# Combine to equivalence classes
#
# Now we know that p, q are combinable
#
ep = eqs[p]
eq = eqs[q]
if eq is not ep:
if len(eq) > len(ep):
eq, ep = ep, eq
ep.extend(eq)
for q in eq:
eqs[q] = ep
return eqs
def finalize(eqs):
csbyid = {} # Composite state by identity of atomic state list
csbyas = {} # Composite state by atomic state
i = 0
for eq in list(eqs.values()):
ideq = id(eq)
if ideq not in csbyid:
c = 'MS%d' % i
i += 1
csbyid[ideq] = eq[0], c
for s in eq:
csbyas[s] = c
fsa = self.__class__(csbyas[self.start_state])
fsa.final_states = {}
for cs0, cst in list(csbyid.values()):
fsa.table[cst] = trans = {}
for a, s in list(self.table[cs0].items()):
trans[a] = csbyas[s]
if cs0 in finals:
fsa.final_states[cst] = 1
return fsa
if self.is_updated:
self.make_deterministic()
tctck = self._tctck = self.get_transition_classes()
self.is_updated = 0
else:
tctck = self._tctck
tc, tck = tctck
tcv = list(tc.values())
PS = markall(finals, tcv, self.table)
eqs = combine(tcv, PS)
fsa = finalize(eqs)
return fsa
def new_composite(self, args):
cs = CompositeState(list(dict([(arg, 1) for arg in args]).keys()))
if len(cs) == 1:
return args[0]
try:
return self.composite_memo[cs]
except KeyError:
self.composite_memo[cs] = cs
self.unresolved_composites.append(cs)
return cs
def pp(self):
ks = list(self.table.keys())
ks.sort()
num = dict([(s, i) for i, s in enumerate(ks)])
for s in ks:
k = self.table[s]
print('%d: %s' % (num[s], s))
cs = list(k.keys())
cs.sort()
for c in cs:
v = k[c]
print(' %r -> #%d: %s' % (c, num[v], v))
class CompositeState(tuple):
pass
Zerion Mini Shell 1.0