// returns the state reached from currState when reading c private static int GetNextState(int currState, char c, Automaton <BDD> dfa, CharSetSolver solver) { foreach (var move in dfa.GetNonepsilonMovesFrom(currState)) { if (solver.IsSatisfiable(solver.MkAnd(move.Label, solver.MkCharConstraint(false, c)))) { return(move.TargetState); } } return(-1); }
internal static void ComputeModels( string currStr, int currState, Automaton <BDD> dfa, List <int> finalStates, HashSet <char> alphabet, CharSetSolver solver, List <string> positive, List <string> negative) { if (currStr.Length >= 8) { return; } if (currState == -1 || !finalStates.Contains(currState)) { negative.Add(currStr); } else { positive.Add(currStr); } foreach (char ch in alphabet) { if (currState == -1) { ComputeModels(currStr + ch, currState, dfa, finalStates, alphabet, solver, positive, negative); } else { bool found = false; foreach (var move in dfa.GetMovesFrom(currState)) { if (solver.IsSatisfiable(solver.MkAnd(move.Label, solver.MkCharConstraint(false, ch)))) { found = true; ComputeModels(currStr + ch, move.TargetState, dfa, finalStates, alphabet, solver, positive, negative); break; } } if (!found) { ComputeModels(currStr + ch, -1, dfa, finalStates, alphabet, solver, positive, negative); } } } }
/// <summary> /// Based on paper /// Order-n correction for regular langauges, http://dl.acm.org/citation.cfm?id=360995 /// </summary> /// <param name="str">input string</param> /// <param name="automaton">dfa for which you want to compute the distance</param> /// <param name="solver">character solver</param> /// <param name="bound">depth of search for max string insertion</param> /// <param name="distance">outputs the distance</param> /// <returns>the closest string to str in automaton</returns> public static string GetClosestElement(string str, Automaton<BDD> automaton, CharSetSolver solver, int bound, out int distance, bool checkDeterminism = true) { //bound = Math.Min(bound, str.Length); var input = str.ToCharArray(); var chars = new HashSet<char>(input); var maxl = input.Length+1; if(automaton.IsEmpty) throw new AutomataException("automaton must be nonempty"); if (checkDeterminism && !automaton.IsDeterministic) throw new AutomataException("automaton must be deterministic"); //Compute P(T,S) L(T,S,c) var lstates= automaton.States.ToList(); lstates.Sort(); var states = lstates.ToArray(); var stToInd = new Dictionary<int, int>(states.Length+1); for (int i = 0; i < states.Length; i++) stToInd[states[i]] = i; var Pold = new int[states.Length, states.Length]; var P1 = new bool[states.Length, states.Length]; //Records the transition relation var Pnew = new int[states.Length, states.Length]; var Lold=new Dictionary<char,bool[,]>(); var Lnew = new Dictionary<char, bool[ ,]>(); #region Initialize P L foreach (var c in chars) { Lold[c] = new bool[states.Length, states.Length]; Lnew[c] = new bool[states.Length, states.Length]; } foreach (var stT in automaton.States) { var T = stToInd[stT]; foreach (var stS in automaton.States) { var S = stToInd[stS]; if (T == S) { Pold[S, T] = 0; char wit; P1[S, T] = MoveFromStoT(stS, stT, automaton, solver, out wit); foreach (var c in chars) if (P1[S, T] && MoveFromStoTContainsC(c, stS, stT, automaton, solver)) Lold[c][S, T] = true; else Lold[c][S, T] = false; } else { char wit; if (MoveFromStoT(stS, stT, automaton, solver, out wit)) { Pold[S, T] = 1; P1[S, T] = true; foreach (var c in chars) if (MoveFromStoTContainsC(c, stS, stT, automaton, solver)) Lold[c][S, T] = true; else Lold[c][S, T] = false; } else { Pold[S, T] = int.MaxValue; P1[S, T] = false; foreach (var c in chars) Lold[c][S, T] = false; } } } } #endregion //solver.ShowGraph(automaton,"as"); //Inductive step for(int k=1;k<=bound;k++){ foreach (var stT in automaton.States) { var T = stToInd[stT]; foreach (var stS in automaton.States) { var S = stToInd[stS]; if (Pold[S, T] == int.MaxValue) { bool found=false; foreach (var move in automaton.GetMovesFrom(stS)) { var stk = move.TargetState; var K = stToInd[stk]; if (Pold[K, T] != int.MaxValue) if (P1[S, K]) { found = true; Pnew[S, T] = Pold[K, T] + 1; foreach (var c in chars) Lnew[c][S, T] = Lold[c][K, T] || solver.IsSatisfiable(solver.MkAnd(move.Label,solver.MkCharConstraint(c))); } } if (!found) { Pnew[S, T] = Pold[S, T]; foreach (var c in chars) Lnew[c][S, T] = Lold[c][S, T]; } } else { Pnew[S, T] = Pold[S, T]; foreach (var c in chars) Lnew[c][S, T] = Lold[c][S, T]; } } } Pold = Pnew; Pnew=new int[states.Length, states.Length]; foreach (var c in chars) Lold[c] = Lnew[c]; Lnew = new Dictionary<char, bool[,]>(); foreach (var c in chars) Lnew[c] = new bool[states.Length, states.Length]; } //Initialize table for value 0 Pair<int, int>[,] F = new Pair<int, int>[maxl, automaton.StateCount]; foreach (var st in automaton.States) { var T = stToInd[st]; if (st == automaton.InitialState) F[0, T] = new Pair<int, int>(0, -1); else F[0, T] = new Pair<int, int>(int.MaxValue, -1); } //solver.ShowGraph(automaton,"aa"); //Dynamic programming loop List<int> stateList = new List<int>(); for (int j = 1; j < maxl; j++) { var aj = input[j - 1]; foreach (var stT in automaton.States) { var T = stToInd[stT]; int min = int.MaxValue; int minSt = -1; foreach (var stS in automaton.States) { var S = stToInd[stS]; var pts = Pold[S, T]; if (pts != int.MaxValue) { var ltsc = Lold[aj][S, T] ? 1 : 0; int vts = pts == 0 ? 1 - ltsc : pts - ltsc; var fjm1t = F[j - 1, S]; int expr = fjm1t.First + vts; if (fjm1t.First == int.MaxValue || vts == int.MaxValue) expr = int.MaxValue; else if (expr <= min) { min = expr; minSt = S; if (min == 0) break; } } } F[j, T] = new Pair<int, int>(min, minSt); } } //Iteration over final states int minAcc = int.MaxValue; int minState = -1; foreach (var st in automaton.GetFinalStates()) { var S = stToInd[st]; if (F[input.Length, S].First < minAcc) { minAcc = F[input.Length, S].First; minState = F[input.Length, S].Second; minState = S; } } var minString =""; int curr = minState; int strindex = input.Length; while (strindex > 0) { var f = F[strindex, curr]; var aj = input[strindex-1]; var pts = Pold[f.Second,curr]; var ltsc = Lold[aj][f.Second,curr] ? 1 : 0; string vts = pts == 0 ? ((ltsc == 1)? aj.ToString():"") : ((ltsc == 1) ? ShortStringStoTwithC(aj, states[f.Second], states[curr], automaton, bound, solver) : ShortStringStoT(states[f.Second], states[curr], automaton, bound, solver)); minString = vts + minString; curr = f.Second; strindex--; } distance=minAcc; return minString; }
//check if delta(S,T,c) exists static bool MoveFromStoTContainsC(char c, int S, int T, Automaton<BDD> aut, CharSetSolver solver, out char witness) { var ccond = solver.MkCharConstraint(c); foreach (var move in aut.GetMovesFrom(S)) if (move.TargetState == T) { if (solver.IsSatisfiable(solver.MkAnd(move.Label, ccond))) { witness = c; return true; } else foreach (var w in solver.GenerateAllCharacters(move.Label, false)) { witness = w; return true; } } witness = c; return false; }
//check if delta(S,T,c) exists static bool MoveFromStoTContainsC(char c, int S, int T, Automaton<BDD> aut, CharSetSolver solver) { var ccond = solver.MkCharConstraint(c); foreach(var move in aut.GetMovesFrom(S)) if (move.TargetState == T) if (solver.IsSatisfiable(solver.MkAnd(move.Label, ccond))) return true; return false; }
internal static void ComputeModels( string currStr, int currState, Automaton<BDD> dfa, List<int> finalStates, HashSet<char> alphabet, CharSetSolver solver, List<string> positive, List<string> negative) { if (currStr.Length >= 8) return; if (currState == -1 || !finalStates.Contains(currState)) negative.Add(currStr); else positive.Add(currStr); foreach (char ch in alphabet) { if (currState == -1) ComputeModels(currStr + ch, currState, dfa, finalStates, alphabet, solver, positive, negative); else { bool found = false; foreach (var move in dfa.GetMovesFrom(currState)) { if (solver.IsSatisfiable(solver.MkAnd(move.Label, solver.MkCharConstraint(false, ch)))) { found = true; ComputeModels(currStr + ch, move.TargetState, dfa, finalStates, alphabet, solver, positive, negative); break; } } if (!found) ComputeModels(currStr + ch, -1, dfa, finalStates, alphabet, solver, positive, negative); } } }
// returns the state reached from currState when reading c private static int GetNextState(int currState, char c, Automaton<BDD> dfa, CharSetSolver solver) { foreach (var move in dfa.GetNonepsilonMovesFrom(currState)) if (solver.IsSatisfiable(solver.MkAnd(move.Label, solver.MkCharConstraint(false, c)))) return move.TargetState; return -1; }
// looks for an edit at depth "depth" // returns false and null in bestScript if no edit is found at depth "depth" // returns false and not null in bestScript if found // returns true if timeout internal static bool GetDFAEditScriptTimeout( Automaton<BDD> dfa1, Automaton<BDD> dfa2, HashSet<char> al, CharSetSolver solver, List<long> editScriptHash, List<DFAEdit> editList, int depth, long timeout, Stopwatch sw, Pair<IEnumerable<string>, IEnumerable<string>> tests, double dfa1density, int totalCost, DFAEditScript bestScript, Dictionary<int, int> stateNamesMapping) { // check timer if (sw.ElapsedMilliseconds > timeout) return true; //Compute worst case distance, call finalScript with this value? int dist = (dfa1.StateCount + dfa2.StateCount) * (al.Count + 1); //Stop if no more moves left if (depth == 0) { if (DFAUtilities.ApproximateMNEquivalent(tests, dfa1density, dfa2, al, solver) && dfa2.IsEquivalentWith(dfa1, solver)) //check if totalCost < finalScript cost and replace if needed if (bestScript.script == null || totalCost < bestScript.GetCost()) bestScript.script = ObjectCopier.Clone<List<DFAEdit>>(editList); return false; } DFAEdit edit = null; #region Flip one move target state foreach (var move in dfa2.GetMoves()) { //Creaty copy of the moves without current move var movesWithoutCurrMove = dfa2.GetMoves().ToList(); movesWithoutCurrMove.Remove(move); //Redirect every ch belonging to move condition foreach (var c in solver.GenerateAllCharacters(move.Label, false)) { long hash = IntegerUtil.PairToInt(move.SourceState, c - 97) + dfa2.StateCount; if (CanAdd(hash, editScriptHash)) { editScriptHash.Insert(0, hash); //Local copy of moves var newMoves = movesWithoutCurrMove.ToList(); var newMoveCondition = solver.MkCharConstraint(false, c); #region Remove ch from current move var andCond = solver.MkAnd(move.Label, solver.MkNot(newMoveCondition)); //add back move without ch iff satisfiable if (solver.IsSatisfiable(andCond)) newMoves.Add(new Move<BDD>(move.SourceState, move.TargetState, andCond)); #endregion #region Redirect c to a different state foreach (var state in dfa2.States) if (state != move.TargetState) { var newMovesComplete = newMoves.ToList(); newMovesComplete.Add(new Move<BDD>(move.SourceState, state, newMoveCondition)); var dfa2new = Automaton<BDD>.Create(dfa2.InitialState, dfa2.GetFinalStates(), newMovesComplete); edit = new DFAEditMove(stateNamesMapping[move.SourceState], stateNamesMapping[state], c); editList.Insert(0, edit); if (GetDFAEditScriptTimeout(dfa1, dfa2new, al, solver, editScriptHash, editList, depth - 1, timeout, sw, tests, dfa1density, totalCost + edit.GetCost(), bestScript, stateNamesMapping)) return true; editList.RemoveAt(0); } #endregion editScriptHash.RemoveAt(0); } } } #endregion #region Flip one state from fin to non fin foreach (var state in dfa2.States) { if (CanAdd(state, editScriptHash)) { //flip its final non final status editScriptHash.Insert(0, state); var newFinalStates = new HashSet<int>(dfa2.GetFinalStates()); Automaton<BDD> dfa2new = null; if (dfa2.GetFinalStates().Contains(state)) { edit = new DFAEditState(stateNamesMapping[state], false); editList.Insert(0, edit); newFinalStates.Remove(state); dfa2new = Automaton<BDD>.Create(dfa2.InitialState, newFinalStates, dfa2.GetMoves()); } else { edit = new DFAEditState(stateNamesMapping[state], true); editList.Insert(0, edit); newFinalStates.Add(state); dfa2new = Automaton<BDD>.Create(dfa2.InitialState, newFinalStates, dfa2.GetMoves()); } if (GetDFAEditScriptTimeout(dfa1, dfa2new, al, solver, editScriptHash, editList, depth - 1, timeout, sw, tests, dfa1density, totalCost + edit.GetCost(), bestScript, stateNamesMapping)) return true; editScriptHash.RemoveAt(0); editList.RemoveAt(0); } } #endregion return false; }
// looks for an edit at depth "depth" // returns false and null in bestScript if no edit is found at depth "depth" // returns false and not null in bestScript if found // returns true if timeout internal static bool GetDFAEditScriptTimeout( Automaton <BDD> dfa1, Automaton <BDD> dfa2, HashSet <char> al, CharSetSolver solver, List <long> editScriptHash, List <DFAEdit> editList, int depth, long timeout, Stopwatch sw, Pair <IEnumerable <string>, IEnumerable <string> > tests, double dfa1density, int totalCost, DFAEditScript bestScript, Dictionary <int, int> stateNamesMapping) { // check timer if (sw.ElapsedMilliseconds > timeout) { return(true); } //Compute worst case distance, call finalScript with this value? int dist = (dfa1.StateCount + dfa2.StateCount) * (al.Count + 1); //Stop if no more moves left if (depth == 0) { if (DFAUtilities.ApproximateMNEquivalent(tests, dfa1density, dfa2, al, solver) && dfa2.IsEquivalentWith(dfa1, solver)) { //check if totalCost < finalScript cost and replace if needed if (bestScript.script == null || totalCost < bestScript.GetCost()) { bestScript.script = ObjectCopier.Clone <List <DFAEdit> >(editList); } } return(false); } DFAEdit edit = null; #region Flip one move target state foreach (var move in dfa2.GetMoves()) { //Creaty copy of the moves without current move var movesWithoutCurrMove = dfa2.GetMoves().ToList(); movesWithoutCurrMove.Remove(move); //Redirect every ch belonging to move condition foreach (var c in solver.GenerateAllCharacters(move.Label, false)) { long hash = IntegerUtil.PairToInt(move.SourceState, c - 97) + dfa2.StateCount; if (CanAdd(hash, editScriptHash)) { editScriptHash.Insert(0, hash); //Local copy of moves var newMoves = movesWithoutCurrMove.ToList(); var newMoveCondition = solver.MkCharConstraint(false, c); #region Remove ch from current move var andCond = solver.MkAnd(move.Label, solver.MkNot(newMoveCondition)); //add back move without ch iff satisfiable if (solver.IsSatisfiable(andCond)) { newMoves.Add(new Move <BDD>(move.SourceState, move.TargetState, andCond)); } #endregion #region Redirect c to a different state foreach (var state in dfa2.States) { if (state != move.TargetState) { var newMovesComplete = newMoves.ToList(); newMovesComplete.Add(new Move <BDD>(move.SourceState, state, newMoveCondition)); var dfa2new = Automaton <BDD> .Create(dfa2.InitialState, dfa2.GetFinalStates(), newMovesComplete); edit = new DFAEditMove(stateNamesMapping[move.SourceState], stateNamesMapping[state], c); editList.Insert(0, edit); if (GetDFAEditScriptTimeout(dfa1, dfa2new, al, solver, editScriptHash, editList, depth - 1, timeout, sw, tests, dfa1density, totalCost + edit.GetCost(), bestScript, stateNamesMapping)) { return(true); } editList.RemoveAt(0); } } #endregion editScriptHash.RemoveAt(0); } } } #endregion #region Flip one state from fin to non fin foreach (var state in dfa2.States) { if (CanAdd(state, editScriptHash)) { //flip its final non final status editScriptHash.Insert(0, state); var newFinalStates = new HashSet <int>(dfa2.GetFinalStates()); Automaton <BDD> dfa2new = null; if (dfa2.GetFinalStates().Contains(state)) { edit = new DFAEditState(stateNamesMapping[state], false); editList.Insert(0, edit); newFinalStates.Remove(state); dfa2new = Automaton <BDD> .Create(dfa2.InitialState, newFinalStates, dfa2.GetMoves()); } else { edit = new DFAEditState(stateNamesMapping[state], true); editList.Insert(0, edit); newFinalStates.Add(state); dfa2new = Automaton <BDD> .Create(dfa2.InitialState, newFinalStates, dfa2.GetMoves()); } if (GetDFAEditScriptTimeout(dfa1, dfa2new, al, solver, editScriptHash, editList, depth - 1, timeout, sw, tests, dfa1density, totalCost + edit.GetCost(), bestScript, stateNamesMapping)) { return(true); } editScriptHash.RemoveAt(0); editList.RemoveAt(0); } } #endregion return(false); }