/// <summary> /// The sink state will be the state with the largest id. /// </summary> public ThreeAutomaton <S> MakeTotal() { var aut = this; int deadState = aut.maxState + 1; var newMoves = new List <Move <S> >(); foreach (int state in aut.States) { var cond = algebra.MkNot(algebra.MkOr(aut.EnumerateConditions(state))); if (algebra.IsSatisfiable(cond)) { newMoves.Add(Move <S> .Create(state, deadState, cond)); } } if (newMoves.Count == 0) { return(this); } newMoves.Add(Move <S> .Create(deadState, deadState, algebra.True)); newMoves.AddRange(GetMoves()); return(ThreeAutomaton <S> .Create(algebra, aut.initialState, aut.rejectingStateSet, aut.acceptingStateSet, newMoves)); }
/// <summary> /// Returns true iff this automaton and another automaton B are equivalent /// </summary> /// <param name="B">another autonmaton</param> public bool IsEquivalentWith(ThreeAutomaton <S> B, IBooleanAlgebra <S> solver) { Automaton <S> accA = Automaton <S> .Create(algebra, this.initialState, this.acceptingStateSet, this.GetMoves()); Automaton <S> accB = Automaton <S> .Create(algebra, B.initialState, B.acceptingStateSet, B.GetMoves()); if (!accA.IsEquivalentWith(accB)) { return(false); } Automaton <S> rejA = Automaton <S> .Create(algebra, this.initialState, this.rejectingStateSet, this.GetMoves()); Automaton <S> rejB = Automaton <S> .Create(algebra, B.initialState, B.rejectingStateSet, B.GetMoves()); return(rejA.IsEquivalentWith(rejB)); }
private bool AreDistinguishable(ThreeAutomaton <S> fa, Equivalence E, Tuple <int, int> pq, IBooleanAlgebraPositive <S> solver) { foreach (Move <S> from_p in fa.GetMovesFrom(pq.Item1)) { foreach (Move <S> from_q in fa.GetMovesFrom(pq.Item2)) { if (from_p.TargetState != from_q.TargetState && !E.AreEquiv(from_p.TargetState, from_q.TargetState)) { if (solver.IsSatisfiable(solver.MkAnd(from_p.Label, from_q.Label))) { return(true); } } } } return(false); }
/// <summary> /// Extension of standard minimization of FAs, use timeout. /// </summary> ThreeAutomaton <S> MinimizeClassical(IBooleanAlgebra <S> solver, int timeout) { var fa = this.MakeTotal(); Equivalence E = new Equivalence(); //initialize E, all nonfinal states are equivalent //and all final states are equivalent and all dontcare are equivalent List <int> stateList = new List <int>(fa.States); for (int i = 0; i < stateList.Count; i++) { //E.Add(stateList[i], stateList[i]); for (int j = 0; j < stateList.Count; j++) { int p = stateList[i]; int q = stateList[j]; bool pIsFinal = fa.IsFinalState(p); bool qIsFinal = fa.IsFinalState(q); if (pIsFinal == qIsFinal) { if (pIsFinal) { E.Add(p, q); } else { bool pIsRej = fa.IsRejectingState(p); bool qIsRej = fa.IsRejectingState(q); if (pIsRej == qIsRej) { E.Add(p, q); } } } } } //refine E bool continueRefinement = true; List <int> statesList = new List <int>(fa.States); while (continueRefinement) { continueRefinement = false; for (int i = 0; i < statesList.Count; i++) { for (int j = 0; j < statesList.Count; j++) { Tuple <int, int> pq = new Tuple <int, int>(statesList[i], statesList[j]); if (E.Contains(pq)) { if (pq.Item1 != pq.Item2 && AreDistinguishable(fa, E, pq, solver)) { E.Remove(pq); continueRefinement = true; } } } } } //create id's for equivalence classes Dictionary <int, int> equivIdMap = new Dictionary <int, int>(); List <int> mfaStates = new List <int>(); foreach (Tuple <int, int> pq in E) { int equivId; if (equivIdMap.TryGetValue(pq.Item1, out equivId)) { equivIdMap[pq.Item2] = equivId; } else if (equivIdMap.TryGetValue(pq.Item2, out equivId)) { equivIdMap[pq.Item1] = equivId; } else { equivIdMap[pq.Item1] = pq.Item1; equivIdMap[pq.Item2] = pq.Item1; mfaStates.Add(pq.Item1); } } //remaining states map to themselves foreach (int state in fa.States) { if (!equivIdMap.ContainsKey(state)) { equivIdMap[state] = state; mfaStates.Add(state); } } int mfaInitialState = equivIdMap[fa.InitialState]; //group together transition conditions for transitions on equivalent states Dictionary <Tuple <int, int>, S> combinedConditionMap = new Dictionary <Tuple <int, int>, S>(); foreach (int state in fa.States) { int fromStateId = equivIdMap[state]; foreach (Move <S> trans in fa.GetMovesFrom(state)) { int toStateId = equivIdMap[trans.TargetState]; S cond; var p = new Tuple <int, int>(fromStateId, toStateId); if (combinedConditionMap.TryGetValue(p, out cond)) { combinedConditionMap[p] = solver.MkOr(cond, trans.Label); } else { combinedConditionMap[p] = trans.Label; } } } //form the transitions of the mfa List <Move <S> > mfaTransitions = new List <Move <S> >(); foreach (var kv in combinedConditionMap) { mfaTransitions.Add(Move <S> .Create(kv.Key.Item1, kv.Key.Item2, kv.Value)); } //accepting states and rejecting HashSet <int> mfaAccStates = new HashSet <int>(); HashSet <int> mfaRejStates = new HashSet <int>(); foreach (int state in acceptingStateSet) { mfaAccStates.Add(equivIdMap[state]); } foreach (int state in rejectingStateSet) { mfaRejStates.Add(equivIdMap[state]); } return(ThreeAutomaton <S> .Create(algebra, mfaInitialState, mfaRejStates, mfaAccStates, mfaTransitions)); }
/// <summary> /// Make a complement of the automaton. /// Assumes that the automaton is deterministic, otherwise throws AutomataException. /// </summary> /// <param name="solver">solver for character constraints</param> /// <returns>Complement of this automaton</returns> public ThreeAutomaton <S> MkComplement() { return(ThreeAutomaton <S> .Create(algebra, initialState, acceptingStateSet, rejectingStateSet, this.GetMoves())); }
/// <summary> /// Creates the automaton that accepts the union of L(this) and L(B). /// Uses additional epsilon transitions and does not need the solver for S. /// </summary> /// <param name="B">another automaton</param> public ThreeAutomaton <S> Union(ThreeAutomaton <S> B, IBooleanAlgebra <S> solver) { return(MkSum(this, B, solver)); }
/// <summary> /// Creates the automaton that accepts the intersection of L(this) and L(B). /// </summary> /// <param name="B">another automaton</param> /// <param name="solver">boolean algebra solver over S</param> public ThreeAutomaton <S> Intersect(ThreeAutomaton <S> B, IBooleanAlgebra <S> solver) { return(MkProduct(this, B, solver)); }
/// <summary> /// Make a sum (union) of a and b. Produces an automaton a+b such that L(a+b) = L(a) union L(b) /// </summary> public static ThreeAutomaton <S> MkSum(ThreeAutomaton <S> a, ThreeAutomaton <S> b, IBooleanAlgebra <S> solver) { return(MkProduct(a, b, solver, false)); }
public static ThreeAutomaton <S> MkProduct(ThreeAutomaton <S> aut1, ThreeAutomaton <S> aut2, IBooleanAlgebra <S> solver, bool inters) { var a = aut1.MakeTotal(); var b = aut2.MakeTotal(); var stateIdMap = new Dictionary <Tuple <int, int>, int>(); var initPair = new Tuple <int, int>(a.InitialState, b.InitialState); var frontier = new Stack <Tuple <int, int> >(); frontier.Push(initPair); stateIdMap[initPair] = 0; var delta = new Dictionary <int, List <Move <S> > >(); delta[0] = new List <Move <S> >(); var states = new List <int>(); states.Add(0); var accStates = new List <int>(); var rejStates = new List <int>(); if (inters) { if (a.IsFinalState(a.InitialState) && b.IsFinalState(b.InitialState)) { accStates.Add(0); } else if (a.IsRejectingState(a.InitialState) || b.IsRejectingState(b.InitialState)) { rejStates.Add(0); } } else { if (a.IsRejectingState(a.InitialState) && b.IsRejectingState(b.InitialState)) { rejStates.Add(0); } else if (a.IsFinalState(a.InitialState) || b.IsFinalState(b.InitialState)) { accStates.Add(0); } } int n = 1; while (frontier.Count > 0) { var currPair = frontier.Pop(); int source = stateIdMap[currPair]; var outTransitions = delta[source]; foreach (var t1 in a.GetMovesFrom(currPair.Item1)) { foreach (var t2 in b.GetMovesFrom(currPair.Item2)) { var cond = solver.MkAnd(t1.Label, t2.Label); if (!solver.IsSatisfiable(cond)) { continue; //ignore the unsatisfiable move } Tuple <int, int> targetPair = new Tuple <int, int>(t1.TargetState, t2.TargetState); int target; if (!stateIdMap.TryGetValue(targetPair, out target)) { //state has not yet been found target = n; n += 1; stateIdMap[targetPair] = target; states.Add(target); delta[target] = new List <Move <S> >(); frontier.Push(targetPair); if (inters) { if (a.IsFinalState(t1.TargetState) && b.IsFinalState(t2.TargetState)) { accStates.Add(target); } else if (a.IsRejectingState(t1.TargetState) || b.IsRejectingState(t2.TargetState)) { rejStates.Add(target); } } else { if (a.IsRejectingState(t1.TargetState) && b.IsRejectingState(t2.TargetState)) { rejStates.Add(target); } else if (a.IsFinalState(t1.TargetState) || b.IsFinalState(t2.TargetState)) { accStates.Add(target); } } } outTransitions.Add(Move <S> .Create(source, target, cond)); } } } var incomingTransitions = new Dictionary <int, List <Move <S> > >(); foreach (int state in states) { incomingTransitions[state] = new List <Move <S> >(); } foreach (int state in states) { foreach (Move <S> t in delta[state]) { incomingTransitions[t.TargetState].Add(t); } } return(ThreeAutomaton <S> .Create(aut1.algebra, 0, rejStates, accStates, EnumerateMoves(delta))); }
/// <summary> /// Create a three symbolic automaton. /// </summary> /// <param name="initialState">initial state</param> /// <param name="acceptingStates">final states</param> /// <param name="moves">moves</param> /// <returns></returns> public static ThreeAutomaton <S> Create(IBooleanAlgebra <S> algebra, int initialState, IEnumerable <int> rejectingStates, IEnumerable <int> acceptingStates, IEnumerable <Move <S> > moves) { var delta = new Dictionary <int, List <Move <S> > >(); var deltaInv = new Dictionary <int, List <Move <S> > >(); delta[initialState] = new List <Move <S> >(); deltaInv[initialState] = new List <Move <S> >(); int maxState = initialState; foreach (Move <S> move in moves) { if (move.IsEpsilon) { throw new AutomataException("Epsilon transitions not supported."); } if (!delta.ContainsKey(move.SourceState)) { delta[move.SourceState] = new List <Move <S> >(); } if (!delta.ContainsKey(move.TargetState)) { delta[move.TargetState] = new List <Move <S> >(); } if (!deltaInv.ContainsKey(move.SourceState)) { deltaInv[move.SourceState] = new List <Move <S> >(); } if (!deltaInv.ContainsKey(move.TargetState)) { deltaInv[move.TargetState] = new List <Move <S> >(); } delta[move.SourceState].Add(move); deltaInv[move.TargetState].Add(move); maxState = Math.Max(maxState, Math.Max(move.SourceState, move.TargetState)); } HashSet <int> acceptingStateSet = new HashSet <int>(acceptingStates); acceptingStateSet.RemoveWhere(x => !delta.ContainsKey(x)); //remove irrelevant states HashSet <int> rejectingStateSet = new HashSet <int>(rejectingStates); rejectingStateSet.RemoveWhere(x => !delta.ContainsKey(x)); HashSet <int> dontCareStateSet = new HashSet <int>(); foreach (var state in delta.Keys) { if (!acceptingStateSet.Contains(state) && !rejectingStateSet.Contains(state)) { dontCareStateSet.Add(state); } } ThreeAutomaton <S> fsa = new ThreeAutomaton <S>(); fsa.algebra = algebra; fsa.initialState = initialState; fsa.acceptingStateSet = acceptingStateSet; fsa.rejectingStateSet = rejectingStateSet; fsa.dontCareStateSet = dontCareStateSet; fsa.maxState = maxState; fsa.delta = delta; fsa.deltaInv = deltaInv; //TODO add determinism check return(fsa); }