module FSMOpt where
import FSM
import GraphOps
import MUtils(collectByFst,collectBySnd,mapFst,mapSnd,usort)
import qualified IntMap as M
import qualified IntSet as S
import qualified OrdMap as OM
import List(sort,partition)
rmeqstate (n,NFA m) = (n',NFA (M.fromList m'))
where (n',m') = repeat' rmeqstate1 (n,M.toList m)
repeat' f x =
case f x of
(True,x') -> x'
(False,x') -> repeat' f x'
rmeqstate1 ((st,go),m) = (null sml,((s st,s go), m3))
where
m3 = [(st,[(e,s go)|(e,go)<-es])|(st:_,es)<-m2b]
s x= M.lookupWithDefault sm x x
sm = M.fromList sml
sml = smla++smlb
smlb = [(old,new)|(new:ss,_)<-m2b,old<-ss]
smla = [(old,new)|(olds,[(E,new)])<-m2a,old<-olds]
(m2a,m2b) = partition jumpstate m2
m2 = opt m
jumpstate (ss,[(E,g)]) = True
jumpstate _ = False
opt = collectBySnd . mapSnd usort
connectivity (n,NFA m) = (n,fmap next m)
where next = S.fromList . map snd
epsilonconnectivity m = fmap epsnext m
where epsnext ns = S.fromList [s|(E,s)<-ns]
unreachable fsm = sort . S.toList $ all `S.minus` r
where
r = reachable g start
all = S.fromList . map fst . M.toList $ g
((start,_),g) = connectivity fsm
tokenclasses x = collectBySnd . collectByFst . tokenedges . edges $x
tokenedges edges = [(i,sg)|(T (I i),sg)<-edges]
outputedges edges = [(o,sg)|(T (O o),sg)<-edges]
epsilonedges edges = [sg|(E,sg)<-edges]
edges (NFA m) = [(e,(s,g))|(s,es)<-M.toList m,(e,g)<-es]
renumberEdges tclss (NFA ss) = NFA (fmap (usort . mapFst renEdge) ss)
where
renEdge (T (I c)) = case OM.lookup c tcmap of Just i -> T (I i)
renEdge (T (O x)) = T (O x)
renEdge E = E
tcmap = OM.fromList tclss