Example #1
0
        /// <summary>
        /// Returns true iff the DFA is not complete or not a DFA (misses transitions)
        /// </summary>
        /// <param name="dfa"></param>
        /// <param name="al"></param>
        /// <param name="solver"></param>
        /// <returns></returns>
        public static bool ContainsSyntacticMistake(Automaton <BDD> dfa, HashSet <char> al,
                                                    CharSetSolver solver, HashSet <int> missingEdges)
        {
            bool mistake = false;
            var  dfaNorm = DFAUtilities.normalizeDFA(dfa).First;

            foreach (var state in dfaNorm.States)
            {
                HashSet <char> alCopy = new HashSet <char>(al);
                foreach (var move in dfaNorm.GetMovesFrom(state))
                {
                    foreach (var c in solver.GenerateAllCharacters(move.Label, false))
                    {
                        if (!alCopy.Contains(c))
                        {
                            int hash = (int)(Math.Pow(2, move.SourceState) + Math.Pow(3, c - 97)) + dfaNorm.StateCount;
                            mistake = true;
                        }
                        alCopy.Remove(c);
                    }
                }
                if (alCopy.Count > 0)
                {
                    mistake = true;
                }
            }
            return(mistake);
        }
        public static XElement getTwoWordsInstructorFeedback(XElement regex, XElement xAlphabet, XElement first, XElement second)
        {
            string         firstString  = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(first.ToString()))).Value.Trim();
            string         secondString = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(second.ToString()))).Value.Trim();
            HashSet <char> alphabet     = parseAlphabet(xAlphabet);

            CharSetSolver solver  = new CharSetSolver(BitWidth.BV64);
            var           dfaPair = DFAUtilities.parseRegexFromXML(regex, xAlphabet, solver);
            var           dfa     = dfaPair.Second.Determinize(solver).Minimize(solver);

            firstString  = firstString.decodeEpsilon();
            secondString = secondString.decodeEpsilon();
            int  firstState    = DFAUtilities.GetStateAfterString(dfa.InitialState, firstString, dfa, solver);
            int  secondState   = DFAUtilities.GetStateAfterString(dfa.InitialState, secondString, dfa, solver);
            bool areEquivalent = (firstState == secondState);

            if (areEquivalent)
            {
                var suffixDfa = Automaton <BDD> .Create(firstState, dfa.GetFinalStates(), dfa.GetMoves());

                var suffixRegex = solver.ConvertToRegex(suffixDfa);
                suffixRegex = regexToTraditional(suffixRegex);
                return(XElement.Parse(String.Format("<div><feedback> The words '{0}' and '{1}' are equivalent. The language of suffixes is '{2}'</feedback></div>", firstString, secondString, suffixRegex)));
            }
            else
            {
                var shortestDiff = DFAUtilities.GetDifferentiatingWord(firstState, secondState, dfa, alphabet, solver).Second;
                return(XElement.Parse(String.Format("<div><feedback> The words '{0}' and '{1}' are NOT equivalent. The shortest differentiating word is '{2}'</feedback></div>", firstString, secondString, shortestDiff)));
            }
        }
        public static bool canRemoveEdge(Automaton <BDD> nfa, int sourceState, int targetState, CharSetSolver solver, Pair <IEnumerable <string>, IEnumerable <string> > tests, HashSet <char> al)
        {
            List <Move <BDD> > newMoves = new List <Move <BDD> >();

            newMoves = nfa.GetMoves().ToList();
            bool moveExists = false;

            //goes through each move from state1 and remove it if it goes to state2 resp.
            foreach (var move in nfa.GetMovesFrom(sourceState))
            {
                if (move.TargetState == targetState)
                {
                    newMoves.Remove(move);
                    moveExists = true;
                }
            }

            var newNfa = Automaton <BDD> .Create(nfa.InitialState, nfa.GetFinalStates(), newMoves);

            if (moveExists)
            {
                if (DFAUtilities.ApproximateMNEquivalent(tests, 0.5, newNfa, al, solver))
                {
                    return(nfa.IsEquivalentWith(newNfa, solver));
                }
            }
            return(false);
        }
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public NFAEditScript GetNFAOptimalEdit(Automaton <BDD> nfa2)
        {
            NFAEditScript editScript = new NFAEditScript();

            //Start timer
            sw.Start();

            //Normalize NFAs
            var normNfaPair       = DFAUtilities.normalizeDFA(nfa2);
            var normNfa2          = normNfaPair.First;
            var stateNamesMapping = normNfaPair.Second;


            NFAEditScript bestScript = new NFAEditScript();

            bestScript.script = null;

            // increase depth up to maxMoves
            for (int depth = 1; true; depth++)
            {
                var editList = new List <NFAEdit>();
                if (GetNFAEditScriptTimeout(
                        depth, -1, normNfa2,
                        editScript.script, editScript.GetCost(), bestScript))
                {
                    // if hits timeout break and return null
                    break;
                }
                if (bestScript.script != null)
                {
                    bestScript.script.Reverse();
                    sw.Stop();
                    var mappedEditList = new List <NFAEdit>();

                    //fix states name because of normalization
                    foreach (var edit in bestScript.script)
                    {
                        NFAEdit mappedEdit = null;
                        if (edit is NFAEditState)
                        {
                            var castEdit = edit as NFAEditState;
                            mappedEdit = new NFAEditState(stateNamesMapping[castEdit.state], castEdit.makeFinal);
                        }
                        if (edit is NFAEditMove)
                        {
                            var castEdit = edit as NFAEditMove;
                            mappedEdit = new NFAEditMove(
                                stateNamesMapping[castEdit.sourceState],
                                stateNamesMapping[castEdit.newTargetState],
                                castEdit.ch);
                        }
                        mappedEditList.Add(mappedEdit);
                    }
                    return(bestScript);
                }
            }

            return(null);
        }
        public DFAEDFeedback(Automaton <BDD> dfaGoal, Automaton <BDD> dfaAttempt, FeedbackLevel level, HashSet <char> alphabet, DFAEditScript script, double utility, CharSetSolver solver)
            : base(level, alphabet, utility, solver)
        {
            var positiveDifference = dfaGoal.Minus(dfaAttempt, solver).Determinize(solver).Minimize(solver);
            var negativeDifference = dfaAttempt.Minus(dfaGoal, solver).Determinize(solver).Minimize(solver);

            this.counterexample = DFAUtilities.GenerateShortTerm(positiveDifference.IsEmpty ? negativeDifference : positiveDifference, solver);
            this.type           = FeedbackType.DFAED;
            this.script         = script;
        }
Example #6
0
        public static bool compareNfaToRegex(XElement regex, XElement alphabet, XElement attemptNfa)
        {
            CharSetSolver solver         = new CharSetSolver(BitWidth.BV64);
            var           dfaCorrectPair = DFAUtilities.parseRegexFromXML(regex, alphabet, solver);
            var           attempt        = DFAUtilities.parseBlockFromXML(attemptNfa, alphabet, solver);

            var same = dfaCorrectPair.Second.IsEquivalentWith(attempt.Second, solver);

            return(same);
        }
        public static bool canRemoveState(Automaton <BDD> nfa, int state, CharSetSolver solver, Pair <IEnumerable <string>, IEnumerable <string> > tests, HashSet <char> al)
        {
            var newNfa = Automaton <BDD> .Create(nfa.InitialState, nfa.GetFinalStates(), nfa.GetMoves());

            newNfa.RemoveTheState(state);

            if (DFAUtilities.ApproximateMNEquivalent(tests, 0.5, newNfa, al, solver))
            {
                return(nfa.IsEquivalentWith(newNfa, solver));
            }
            return(false);
        }
        public NFAEDFeedback(Automaton <BDD> nfaGoal, Automaton <BDD> nfaAttempt,
                             FeedbackLevel level, HashSet <char> alphabet,
                             NFAEditScript script, CharSetSolver solver)
            : base(level, alphabet, solver)
        {
            //TODO might have to determinize to do this operations
            var positiveDifference = nfaGoal.Minus(nfaAttempt, solver).Determinize(solver).Minimize(solver);
            var negativeDifference = nfaAttempt.Minus(nfaGoal, solver).Determinize(solver).Minimize(solver);

            this.counterexample = DFAUtilities.GenerateShortTerm(positiveDifference.IsEmpty ? negativeDifference : positiveDifference, solver);
            this.script         = script;
        }
        private static HashSet <char> parseAlphabet(XElement xAlphabet)
        {
            xAlphabet = DFAUtilities.RemoveJustNamespaces(xAlphabet);
            HashSet <char> alphabet = new HashSet <char>();

            foreach (var child in xAlphabet.Elements("symbol"))
            {
                char element = Convert.ToChar(child.Value.Trim());
                alphabet.Add(element);
            }
            return(alphabet);
        }
        public static XElement getShortestFeedback(XElement regex, XElement xAlphabet, XElement representative, XElement attemptShortest, XElement maxGrade)
        {
            int           maxG    = int.Parse(maxGrade.Value);
            CharSetSolver solver  = new CharSetSolver(BitWidth.BV64);
            var           dfaPair = DFAUtilities.parseRegexFromXML(regex, xAlphabet, solver);
            var           dfa     = dfaPair.Second.Minimize(solver);

            string representativeString = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(representative.ToString()))).Value.Trim();

            representativeString = representativeString.decodeEpsilon();
            string attemptShortestString = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(attemptShortest.ToString()))).Value.Trim();

            attemptShortestString = attemptShortestString.decodeEpsilon();

            int representativeState  = DFAUtilities.GetStateAfterString(dfa.InitialState, representativeString, dfa, solver);
            int attemptShortestState = DFAUtilities.GetStateAfterString(dfa.InitialState, attemptShortestString, dfa, solver);

            xAlphabet = XElement.Parse(DFAUtilities.RemoveAllNamespaces(xAlphabet.ToString()));
            HashSet <char> alphabet = parseAlphabet(xAlphabet);

            string correctShortest = DFAUtilities.GetRepresentative(representativeState, dfa, alphabet, solver);

            if (correctShortest.Equals(attemptShortestString))
            {
                return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>Correct!</feedback></div>", maxG)));
            }
            else if (attemptShortestState == representativeState)
            {
                if (representativeString.Equals(attemptShortestString))
                {
                    return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>Please provide a different word than the given one</feedback></div>", 0)));
                }
                else if (attemptShortestString.Length > correctShortest.Length)
                {
                    return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>The word '{1}' is in the same equivalence class as '{2}' but there exists a shorter one</feedback></div>", (int)(maxG * 2 / 3), attemptShortestString.emptyToEpsilon(), representativeString.emptyToEpsilon())));
                }
                else
                {
                    return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>The word '{1}' is in the same equivalence class as '{2}' but there exists a <strong>lexicographically smaller</strong> one</feedback></div>", (int)(maxG * 4 / 5), attemptShortestString.emptyToEpsilon(), representativeString.emptyToEpsilon())));
                }
            }
            else
            {
                string feedString = "Incorrect!";//"The Correct Answer is '" + correctShortest + "'";
                return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>{1}</feedback></div>", 0, feedString)));
            }
        }
Example #11
0
        public static Tuple <int, int, string> recursiveHelper(XElement regex, XElement alphabet, XElement attemptRoot)
        {
            var cleanRegex     = XElement.Parse(DFAUtilities.RemoveAllNamespaces(regex.ToString())).Value.Trim();
            var subexpressions = GetSubexpressions(cleanRegex);

            int    total = 1, correct = 0;
            string feedString = "";

            if (!compareNfaToRegex(regex, alphabet, attemptRoot))
            {
                if (!wrong.Contains(cleanRegex))
                {
                    feedString += String.Format("<li> Incorrect definition of '{0}' </li>", cleanRegex);
                }
                wrong.Add(cleanRegex);
            }
            else if (!expressions.Contains(cleanRegex))
            {
                correct++;
            }

            expressions.Add(cleanRegex);

            var states = attemptRoot.Element("stateSet");

            foreach (var s in states.Elements())
            {
                if (s.Name == "block")
                {
                    var subreg = s.Attribute("regex").Value.Trim();
                    if (subexpressions.Contains(subreg))
                    {
                        var tup = recursiveHelper(XElement.Parse("<div>" + subreg + "</div>"), alphabet, s);
                        correct    += tup.Item1;
                        total      += tup.Item2;
                        feedString += tup.Item3;
                    }
                    else
                    {
                        feedString += String.Format("<li> '{0}' is not a subexpression of '{1}' </li>", subreg, cleanRegex);
                    }
                }
            }
            return(Tuple.Create(correct, total, feedString));
        }
        public override string ToString()
        {
            string posWitness = null;
            string negWitness = null;

            if (!positiveDifference.IsEmpty)
            {
                posWitness = DFAUtilities.GenerateShortTerm(positiveDifference, solver);
                return(string.Format("Your NFA does not accept the {0} while the correct solution does.",
                                     posWitness != "" ? "string '<i>" + posWitness + "</i>'" : "empty string"));
            }
            else
            {
                negWitness = DFAUtilities.GenerateShortTerm(negativeDifference, solver);
                return(string.Format("Your NFA accepts the {0} while the correct solution doesn't.",
                                     negWitness != "" ? "string '<i>" + negWitness + "</i>'" : "empty string"));
            }
        }
        public static bool canCollapseStates(Automaton <BDD> nfa, int state1, int state2, CharSetSolver solver, Pair <IEnumerable <string>, IEnumerable <string> > tests, HashSet <char> al)
        {
            var density = DFADensity.GetDFADensity(nfa, al, solver);

            // collapses state2 to state1
            List <Move <BDD> > newMoves = new List <Move <BDD> >();

            foreach (var move in nfa.GetMoves())
            {
                var newSource = move.SourceState;
                var newTarget = move.TargetState;

                if (newSource == state2)
                {
                    newSource = state1;
                }
                if (newTarget == state2)
                {
                    newTarget = state1;
                }

                newMoves.Add(new Move <BDD>(newSource, newTarget, move.Label));
            }

            // replace state2 with state1 if initial state
            // no need to remove state2 from final state list, as it is unreachable
            int newInitialState = nfa.InitialState;

            if (nfa.InitialState == state2)
            {
                newInitialState = state1;
            }

            //makes new Nfa and returns collapse state edit if are equiv
            var newNfa = Automaton <BDD> .Create(newInitialState, nfa.GetFinalStates(), newMoves);

            if (DFAUtilities.ApproximateMNEquivalent(tests, density, newNfa, al, solver))
            {
                return(nfa.IsEquivalentWith(newNfa, solver));
            }
            return(false);
        }
Example #14
0
        public static XElement getFeedback(XElement regex, XElement alphabet, XElement attemptNfa, XElement maxGrade)
        {
            var cleanAttempt = DFAUtilities.RemoveJustNamespaces(attemptNfa).Element("block");

            expressions = new HashSet <string>();
            wrong       = new HashSet <string>();

            var feedString = "<ul>";
            var tup        = recursiveHelper(regex, alphabet, cleanAttempt);

            feedString += tup.Item3 + "</ul>";

            var grade = 1.0 * int.Parse(maxGrade.Value) * tup.Item1 / expressions.Count;

            if (grade == int.Parse(maxGrade.Value))
            {
                feedString = "Correct!";
            }
            return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>{1}</feedback></div>", (int)(Math.Floor(grade)), feedString)));
        }
        // returns an array where a[n] is the number of paths of length n
        private static double[] GetPathsUpToN(Automaton <BDD> dfa, HashSet <char> al, CharSetSolver solver, int n)
        {
            var normDfa1 = DFAUtilities.normalizeDFA(dfa).First;

            int length = 0;

            double[] totPaths    = new double[n + 1];
            var      finalStates = normDfa1.GetFinalStates();

            double[] pathNum = new double[normDfa1.StateCount];
            pathNum[0]  = 1;
            totPaths[0] = finalStates.Contains(0) ? 1 : 0;
            for (int i = 1; i < pathNum.Length; i++)
            {
                pathNum[i] = 0;
            }


            while (length < n)
            {
                double[] oldPathNum = pathNum.ToArray();
                for (int i = 0; i < pathNum.Length; i++)
                {
                    pathNum[i] = 0;
                }

                length++;
                foreach (var state in normDfa1.States)
                {
                    if (oldPathNum[state] > 0)
                    {
                        foreach (var move in normDfa1.GetMovesFrom(state))
                        {
                            int size = 0;
                            //Check if epsilon transition
                            if (move.Label == null)
                            {
                                size = 1;
                            }
                            else
                            {
                                foreach (var v in solver.GenerateAllCharacters(move.Label, false))
                                {
                                    size++;
                                }
                            }

                            pathNum[move.TargetState] += oldPathNum[state] * size;
                        }
                    }
                }

                //totPaths[length] = totPaths[length - 1];
                foreach (var state in finalStates)
                {
                    totPaths[length] += pathNum[state];
                }
            }

            return(totPaths);
        }
        // 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 bool GetNFAEditScriptTimeout(
            int depth, long lastEditHash,
            Automaton <BDD> currentNfa2,
            List <NFAEdit> editList, int scriptCost,
            NFAEditScript bestScript)
        {
            // if timeout return true
            if (sw.ElapsedMilliseconds > timeout)
            {
                return(true);
            }


            //Stop if no more moves left
            if (depth == 0)
            {
                if (DFAUtilities.ApproximateMNEquivalent(tests, nfa1density, currentNfa2, al, solver) && currentNfa2.IsEquivalentWith(nfa1, solver))
                {
                    //check if totalCost < finalScript cost and replace if needed
                    if (bestScript.script == null || scriptCost < bestScript.GetCost())
                    {
                        bestScript.script = ObjectCopier.Clone <List <NFAEdit> >(editList);
                    }
                }
                return(false);
            }

            NFAEdit edit = null;

            long thisEditHash = 0;

            #region Flip one state from fin to non fin
            foreach (var state in currentNfa2.States)
            {
                thisEditHash = state;
                if (CanAdd(thisEditHash, lastEditHash))
                {
                    //flip its final non final status

                    var             newFinalStates = new HashSet <int>(currentNfa2.GetFinalStates());
                    Automaton <BDD> nfa2new        = null;
                    if (currentNfa2.GetFinalStates().Contains(state))
                    {
                        edit = new NFAEditState(state, false);
                        editList.Insert(0, edit);
                        newFinalStates.Remove(state);
                        nfa2new = Automaton <BDD> .Create(currentNfa2.InitialState, newFinalStates, currentNfa2.GetMoves());
                    }
                    else
                    {
                        edit = new NFAEditState(state, true);
                        editList.Insert(0, edit);
                        newFinalStates.Add(state);
                        nfa2new = Automaton <BDD> .Create(currentNfa2.InitialState, newFinalStates, currentNfa2.GetMoves());
                    }

                    if (GetNFAEditScriptTimeout(depth - 1, thisEditHash, nfa2new, editList, scriptCost + edit.GetCost(), bestScript))
                    {
                        return(true);
                    }

                    editList.RemoveAt(0);
                }
            }
            #endregion

            #region Change transition from source state
            currentNfa2 = NFAUtilities.normalizeMoves(currentNfa2, solver);
            foreach (var sourceState in currentNfa2.States)
            {
                HashSet <int> unreachedStates = new HashSet <int>(currentNfa2.States);
                foreach (var moveFromSource in currentNfa2.GetMovesFrom(sourceState))
                {
                    // take all chars in alphabet
                    foreach (var c in al)
                    {
                        long moveHash = currentNfa2.StateCount + IntegerUtil.TripleToInt(sourceState, moveFromSource.TargetState, alphabetMap[c]);
                        thisEditHash = currentNfa2.StateCount + moveHash;
                        if (CanAdd(thisEditHash, lastEditHash))
                        {
                            BDD cCond   = solver.False;
                            BDD newCond = solver.False;

                            //skip epsilon moves
                            if (moveFromSource.Label != null)
                            {
                                // if c in move, remove it and recursion
                                if (solver.Contains(moveFromSource.Label, c))
                                {
                                    cCond   = solver.MkNot(solver.MkCharConstraint(false, c));
                                    newCond = solver.MkAnd(moveFromSource.Label, cCond);
                                }
                                else // if c not in move, add it and recursion
                                {
                                    cCond   = solver.MkCharConstraint(false, c);
                                    newCond = solver.MkOr(moveFromSource.Label, cCond);
                                }

                                var newMoves = new List <Move <BDD> >(currentNfa2.GetMoves());
                                newMoves.Remove(moveFromSource);
                                newMoves.Add(new Move <BDD>(sourceState, moveFromSource.TargetState, newCond));
                                var nfa2new = Automaton <BDD> .Create(currentNfa2.InitialState, currentNfa2.GetFinalStates(), newMoves);

                                edit = new NFAEditMove(sourceState, moveFromSource.TargetState, c);
                                editList.Insert(0, edit);

                                if (GetNFAEditScriptTimeout(depth - 1, thisEditHash, nfa2new, editList, scriptCost + edit.GetCost(), bestScript))
                                {
                                    return(true);
                                }

                                editList.RemoveAt(0);
                            }
                        }
                    }

                    unreachedStates.Remove(moveFromSource.TargetState);
                }

                foreach (var targetState in unreachedStates)
                {
                    //try adding a symbol not in transition
                    foreach (var c in al)
                    {
                        long moveHash = IntegerUtil.TripleToInt(sourceState, targetState, alphabetMap[c]);
                        thisEditHash = currentNfa2.StateCount + moveHash;

                        var moveCond = solver.MkCharConstraint(false, c);
                        var newMoves = new List <Move <BDD> >(currentNfa2.GetMoves());
                        newMoves.Add(new Move <BDD>(sourceState, targetState, moveCond));
                        var nfa2new = Automaton <BDD> .Create(currentNfa2.InitialState, currentNfa2.GetFinalStates(), newMoves);

                        edit = new NFAEditMove(sourceState, targetState, c);
                        editList.Insert(0, edit);

                        //TODO put correct hash
                        if (GetNFAEditScriptTimeout(depth - 1, thisEditHash, nfa2new, editList, scriptCost + edit.GetCost(), bestScript))
                        {
                            return(true);
                        }

                        editList.RemoveAt(0);
                    }
                }
            }
            #endregion

            return(false);
        }
        public static XElement getWordsFeedback(XElement regex, XElement xAlphabet, XElement representative, XElement wordsIn, XElement maxGrade)
        {
            //read inputs
            int              maxG        = int.Parse(maxGrade.Value);
            List <string>    wordsInList = new List <String>();
            HashSet <string> usedWords   = new HashSet <string>();

            foreach (var wordElement in wordsIn.Elements())
            {
                string w = wordElement.Value;
                if (w.Length > 75)
                {
                    w = w.Substring(0, 75);                //limit word length
                }
                w = w.decodeEpsilon();
                wordsInList.Add(w);
            }

            HashSet <char> alphabet       = parseAlphabet(xAlphabet);
            string         alphabetString = alphabetToString(alphabet);
            CharSetSolver  solver         = new CharSetSolver(BitWidth.BV64);
            var            dfaPair        = DFAUtilities.parseRegexFromXML(regex, xAlphabet, solver);
            var            dfa            = dfaPair.Second.Minimize(solver);

            string representativeString = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(representative.ToString()))).Value.Trim();

            representativeString = representativeString.decodeEpsilon();
            int representativeState = DFAUtilities.GetStateAfterString(dfa.InitialState, representativeString, dfa, solver);

            string feedString = "<ul>";
            int    correct    = 0;
            int    total      = wordsInList.Count;

            usedWords.Add(representativeString);
            foreach (string s in wordsInList)
            {
                //TODO: Check string only contains valid characters
                if (usedWords.Contains(s))
                {
                    if (s.Equals(representativeString))
                    {
                        feedString += String.Format("<li> The word '{0}' was provided by the instructor </li>", s.emptyToEpsilon());
                    }
                    else
                    {
                        feedString += String.Format("<li> The word '{0}' was already used </li>", s.emptyToEpsilon());
                    }
                    continue;
                }
                bool overValidAlphabet = true;
                foreach (char c in s)
                {
                    if (!alphabet.Contains(c))
                    {
                        overValidAlphabet = false;
                    }
                }
                if (!overValidAlphabet)
                {
                    feedString += String.Format("<li> The word '{0}' is not over the alphabet {1} </li>", s.emptyToEpsilon(), alphabetString);
                    continue;
                }
                usedWords.Add(s);
                int wordState = DFAUtilities.GetStateAfterString(dfa.InitialState, s, dfa, solver);
                if (wordState == representativeState)
                {
                    correct++;
                }
                else
                {
                    feedString += String.Format("<li> The word '{0}' is not in the same equivalence class as '{1}' </li>", s.emptyToEpsilon(), representativeString.emptyToEpsilon());
                }
            }

            feedString += "</ul>";
            var grade = 1.0 * int.Parse(maxGrade.Value) * correct / total;

            if (grade == maxG)
            {
                feedString = "Correct!";
            }
            return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>{1}</feedback></div>", (int)(Math.Ceiling(grade)), feedString)));
        }
Example #18
0
        /// <summary>
        /// Finds min edit distance script between DFAs if operation
        /// takes less than timeout ms
        /// </summary>
        /// <param name="dfa1"></param>
        /// <param name="dfa2"></param>
        /// <param name="al"></param>
        /// <param name="solver"></param>
        /// <param name="timeout"></param>
        /// <param name="sb"></param>
        /// <returns></returns>
        public static DFAEditScript GetDFAOptimalEdit( // copy
            Automaton <BDD> dfa1, Automaton <BDD> dfa2,
            HashSet <char> al, CharSetSolver solver, long timeout,
            StringBuilder sb)
        {
            //Contract.Assert(dfa1.IsDeterministic);
            //Contract.Assert(dfa2.IsDeterministic);

            DFAEditScript editScript = new DFAEditScript();

            #region Add states to dfa2 to make it at least as dfa1
            BDD fullAlphabetCondition = BDDOf(al, solver);

            //Normalize the DFA giving only names from 0 to |States|-1
            var normDfaPair   = DFAUtilities.normalizeDFA(dfa2);
            var dfa2augmented = normDfaPair.First;
            //solver.SaveAsDot(dfa2augmented, "aaaa");
            var stateNamesMapping = normDfaPair.Second;

            //Add states to make dfa2 have the |dfa2.States|>= |dfa1.States|
            var newMoves = new List <Move <BDD> >(dfa2augmented.GetMoves());

            for (int i = 1; i <= dfa1.StateCount - dfa2augmented.StateCount; i++)
            {
                int newStateName = dfa2augmented.MaxState + i;
                //Pick the next available name to be added
                stateNamesMapping[newStateName] = dfa2.MaxState + i;
                //save the operation in the script
                editScript.script.Insert(0, new DFAAddState(dfa2.MaxState + i));
                newMoves.Add(new Move <BDD>(newStateName, newStateName, fullAlphabetCondition));
                newStateName++;
            }
            //Create the new DFA with the added states
            dfa2augmented = Automaton <BDD> .Create(dfa2augmented.InitialState, dfa2augmented.GetFinalStates().ToList(), newMoves);

            #endregion

            int maxScore      = (dfa1.StateCount + dfa2augmented.StateCount) * (al.Count + 1);
            int oldScirptSize = editScript.script.Count;

            //Start with the internal script equals to null, at the end bestScript.Script will contain the best script
            DFAEditScript bestScript = new DFAEditScript();
            bestScript.script = null;
            Stopwatch sw = new Stopwatch();
            sw.Start();

            // Iteratively check if there exists an edit of a given depth
            for (int depth = 1; true; depth++)
            {
                var editList = new List <DFAEdit>();
                if (GetDFAEditScriptTimeout(
                        dfa1, dfa2augmented, al, solver,
                        new List <long>(), editScript.script,
                        depth, timeout, sw, DFAUtilities.MyHillTestGeneration(al, dfa1, solver),
                        DFADensity.GetDFADensity(dfa1, al, solver),
                        editScript.GetCost(), bestScript, stateNamesMapping))
                {
                    // if hits timeout break and return null
                    break;
                }
                if (bestScript.script != null)
                {
                    bestScript.script.Reverse();
                    sw.Stop();
                    return(bestScript);
                }
            }

            sw.Stop();
            return(null);
        }
        public static Pair <HashSet <char>, Automaton <BDD> > parseRegexFromXML(XElement regex, XElement alphabet, CharSetSolver solver)
        {
            HashSet <char> al          = new HashSet <char>();
            XElement       xmlAlphabet = XElement.Parse(RemoveAllNamespaces(alphabet.ToString()));

            string alRex = "";
            bool   first = true;

            foreach (XElement child in xmlAlphabet.Elements())
            {
                char element = Convert.ToChar(child.Value);
                al.Add(element);
                if (first)
                {
                    first  = false;
                    alRex += element;
                }
                else
                {
                    alRex += "|" + element;
                }
            }

            XElement Regex = XElement.Parse(RemoveAllNamespaces(regex.ToString()));

            string rexpr = Regex.Value.Trim();

            var             escapedRexpr = string.Format(@"^({0})$", rexpr);
            Automaton <BDD> aut          = null;

            try
            {
                aut = solver.Convert(escapedRexpr).RemoveEpsilons(solver.MkOr).Determinize(solver);
            }
            catch (ArgumentException e)
            {
                throw new PDLException("The input is not a well formatted regular expression: " + e.Message);
            }
            catch (AutomataException e)
            {
                throw new PDLException("The input is not a well formatted regular expression: " + e.Message);
            }



            var diff = aut.Intersect(solver.Convert(@"^(" + alRex + @")*$").Complement(solver), solver);

            if (!diff.IsEmpty)
            {
                throw new PDLException(
                          "The regular expression should only accept strings over (" + alRex + ")*. Yours accepts the string '" + DFAUtilities.GenerateShortTerm(diff.Determinize(solver), solver) + "'");
            }

            return(new Pair <HashSet <char>, Automaton <BDD> >(al, aut));
        }
        public override string ToString()
        {
            long enumTimeout = 1000L;

            #region feedback components
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            PDLPred       symmPhi       = null;
            PDLPred       underPhi      = null;
            string        posWitness    = null;
            string        negWitness    = null;
            //If hint or solution try computing the description of the symmdiff
            if (level == FeedbackLevel.Hint || level == FeedbackLevel.Solution)
            {
                //Avoid formulas that are too complex
                var maxSize = 7;
                if (symmetricDifference.StateCount < 15)
                {
                    foreach (var phi1 in pdlEnumerator.SynthesizePDL(alphabet, symmetricDifference, solver, new StringBuilder(), enumTimeout))
                    {
                        var sizePhi1 = phi1.GetFormulaSize();
                        if (sizePhi1 < maxSize && !phi1.IsComplex())
                        {
                            maxSize = sizePhi1;
                            symmPhi = phi1;
                        }
                    }
                }
            }
            //Avoid empty string case and particular string
            if (symmPhi is PDLEmptyString || symmPhi is PDLIsString)
            {
                symmPhi = null;
            }

            //If not minimal try computing and underapprox of symmdiff
            if (symmPhi == null && level != FeedbackLevel.Minimal)
            {
                //Avoid formulas that are too complex
                var minSize = 9;
                if (symmetricDifference.StateCount < 15)
                {
                    foreach (var phi2 in pdlEnumerator.SynthesizeUnderapproximationPDL(alphabet, symmetricDifference, solver, new StringBuilder(), enumTimeout))
                    {
                        var formula  = phi2.First;
                        var sizeForm = formula.GetFormulaSize();
                        if (sizeForm < minSize && !formula.IsComplex())
                        {
                            minSize  = sizeForm;
                            underPhi = formula;
                        }

                        break;
                    }
                }
            }
            //Avoid empty string case and particular string
            if (underPhi is PDLEmptyString || underPhi is PDLIsString)
            {
                underPhi = null;
            }

            if (!positiveDifference.IsEmpty)
            {
                posWitness = DFAUtilities.GenerateShortTerm(positiveDifference, solver);
            }
            else
            {
                negWitness = DFAUtilities.GenerateShortTerm(negativeDifference, solver);
            }
            #endregion

            string result = ""; //string.Format("U: {0}%. ", utility);
            if (symmPhi != null)
            {
                if (symmPhi is PDLEmptyString)
                {
                    result += "Your solution does not behave correctly on the empty string";
                }
                else
                {
                    result += string.Format("Your solution is not correct on this set of strings: <br /> <div align='center'>{0}</div>", PDLUtil.ToEnglishString(symmPhi));
                }
            }
            else
            if (underPhi != null)
            {
                if (underPhi is PDLEmptyString)
                {
                    result += "Your solution does not behave correctly on the empty string";
                }
                else
                {
                    result += string.Format("Your solution is not correct on this set of strings: <br /> <div align='center'>{0}</div>",
                                            PDLUtil.ToEnglishString(underPhi));
                }
            }
            else
            {
                if (posWitness != null)
                {
                    result += string.Format("Your solution does not accept the {0} while the correct solution does.",
                                            posWitness != "" ? "string '<i>" + posWitness + "</i>'" : "empty string");
                }
                else
                {
                    result += string.Format("Your solution accepts the {0} while the correct solution doesn't.",
                                            negWitness != "" ? "string '<i>" + negWitness + "</i>'" : "empty string");
                }
            }
            return(result);
        }
        public static XElement getSameFeedback(XElement regex, XElement xAlphabet, XElement first, XElement second, XElement notEquivalent, XElement reason, XElement maxGrade)
        {
            string         firstString          = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(first.ToString()))).Value.Trim().decodeEpsilon();
            string         secondString         = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(second.ToString()))).Value.Trim().decodeEpsilon();
            string         reasonString         = (XElement.Parse(DFAUtilities.RemoveAllNamespaces(reason.ToString()))).Value.Trim();
            bool           areEquivalentAttempt = int.Parse(notEquivalent.Value) == 1 ? false : true;
            int            maxG     = int.Parse(maxGrade.Value);
            HashSet <char> alphabet = parseAlphabet(xAlphabet);

            CharSetSolver solver  = new CharSetSolver(BitWidth.BV64);
            var           dfaPair = DFAUtilities.parseRegexFromXML(regex, xAlphabet, solver);
            var           dfa     = dfaPair.Second.Minimize(solver);

            int  firstState    = DFAUtilities.GetStateAfterString(dfa.InitialState, firstString, dfa, solver);
            int  secondState   = DFAUtilities.GetStateAfterString(dfa.InitialState, secondString, dfa, solver);
            bool areEquivalent = (firstState == secondState);

            if (areEquivalent != areEquivalentAttempt)
            {
                return(XElement.Parse(string.Format("<div><grade>0</grade><feedback>Wrong equivalency assesment!</feedback></div>")));
            }
            else if (areEquivalent)
            {
                try
                {
                    var suffixDfa = Automaton <BDD> .Create(firstState, dfa.GetFinalStates(), dfa.GetMoves());

                    var reasonDfaPair      = DFAUtilities.parseRegexFromXML(reason, xAlphabet, solver);
                    var dfaGradingFeedback = DFAGrading.GetGrade(suffixDfa, reasonDfaPair.Second, alphabet, solver, 1500, maxG, FeedbackLevel.Minimal, false, false, true);
                    var feedString         = "<div>";
                    foreach (var feed in dfaGradingFeedback.Second)
                    {
                        feedString += string.Format("{0}<br />", feed);
                    }
                    feedString += "</div>";
                    if (maxG == dfaGradingFeedback.First)
                    {
                        return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>Correct!</feedback></div>", maxG)));
                    }
                    else
                    {
                        return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>{1}</feedback></div>", Math.Max((int)(maxG / 3), dfaGradingFeedback.First), feedString)));
                    }
                }
                catch (PDLException pdlex)
                {
                    return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>Parsing Error: {1}</feedback></div>", (int)(maxG / 3), pdlex.Message)));
                }
            }
            else
            {
                // Finding a shortest differentiating word
                var shortestDiff = DFAUtilities.GetDifferentiatingWord(firstState, secondState, dfa, alphabet, solver).Second;
                reasonString = reasonString.decodeEpsilon();
                int  endFirst  = DFAUtilities.GetStateAfterString(firstState, reasonString, dfa, solver);
                int  endSecond = DFAUtilities.GetStateAfterString(secondState, reasonString, dfa, solver);
                bool c1        = dfa.GetFinalStates().Contains(endFirst);
                bool c2        = dfa.GetFinalStates().Contains(endSecond);
                if (c1 ^ c2)
                {
                    return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>Correct!</feedback></div>", maxG)));
                }
                else
                {
                    string feedString = string.Format("The words '{0}' and '{2}' are both {1} by the language", (firstString + reasonString).emptyToEpsilon(), c1 ? "accepted" : "not accepted", (secondString + reasonString).emptyToEpsilon());
                    return(XElement.Parse(string.Format("<div><grade>{0}</grade><feedback>{1}</feedback></div>", (int)(maxG / 3), feedString)));
                }
            }
        }
        public static IEnumerable <Regexp> SynthesizeRegexp(HashSet <char> alphabet, Automaton <BDD> dfa, CharSetSolver s, StringBuilder sb, long timeout)
        {
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"..\..\..\regexpenum.txt"))
            {
                solver    = s;
                numStates = dfa.StateCount;
                alph      = alphabet;

                #region test variables
                StringBuilder sb1             = new StringBuilder();
                int           lim             = 0;
                Stopwatch     membershipTimer = new Stopwatch();
                Stopwatch     equivTimer      = new Stopwatch();
                timer = new Stopwatch();
                timer.Start();
                #endregion


                #region TestSets for equiv
                var mytests  = DFAUtilities.MyHillTestGeneration(alphabet, dfa, solver);
                var posMN    = mytests.First;
                var negMN    = mytests.Second;
                var tests    = DFAUtilities.GetTestSets(dfa, alphabet, solver);
                var positive = tests.First;
                var negative = tests.Second;
                foreach (var t in posMN)
                {
                    positive.Remove(t);
                }
                foreach (var t in negMN)
                {
                    negative.Remove(t);
                }
                #endregion

                #region Sigma Star
                bool fst = true;
                foreach (var c in alph)
                {
                    if (fst)
                    {
                        fst       = false;
                        sigmaStar = new RELabel(c);
                    }
                    else
                    {
                        sigmaStar = new REUnion(sigmaStar, new RELabel(c));
                    }
                }

                sigmaPlus = new REPlus(sigmaStar);
                sigmaStar = new REStar(sigmaStar);
                #endregion

                #region Accessories vars
                maxWidthC     = 0;
                maxSigmaStarC = 0;
                var isSubset             = true;
                HashSet <string> visited = new HashSet <string>();
                HashSet <string> newReg  = new HashSet <string>();
                currUnionEls = new Dictionary <string, Automaton <BDD> >();
                memoDfa      = new Dictionary <string, Automaton <BDD> >();
                List <Regexp> subsetReg = new List <Regexp>();
                #endregion

                for (maxWidth = 1; true; maxWidth++)
                {
                    newReg       = new HashSet <string>();
                    maxSigmaStar = 2;

                    foreach (var regexp in EnumerateRegexp())
                    {
                        #region run for at most timeout
                        if (timer.ElapsedMilliseconds > timeout)
                        {
                            sb.AppendLine("| Timeout");
                            timer.Stop();
                            yield break;
                        }
                        #endregion

                        var re = regexp.Normalize();

                        if (!(visited.Contains(re.ToString())))
                        {
                            visited.Add(re.ToString());

                            sb1 = new StringBuilder();
                            sb1.Append(re.ToString());
                            file.WriteLine(sb1);
                            lim++;

                            #region Membership test
                            membershipTimer.Start();
                            isSubset = CorrectOnNegSet(regexp, negMN);
                            membershipTimer.Stop();
                            #endregion

                            #region equivalence check
                            if (isSubset)
                            {
                                membershipTimer.Start();
                                if (CorrectOnNegSet(regexp, negative))
                                {
                                    if (CorrectOnPosSet(regexp, posMN) && CorrectOnPosSet(regexp, positive))
                                    {
                                        membershipTimer.Stop();
                                        equivTimer.Start();
                                        var rDfa = getDfa(regexp);
                                        memoDfa[regexp.ToString()] = rDfa;

                                        if (rDfa.IsEquivalentWith(dfa, solver))
                                        {
                                            isSubset = false;
                                            equivTimer.Stop();
                                            timer.Stop();

                                            sb.Append("| ");
                                            regexp.ToString(sb);
                                            sb.AppendLine("|");
                                            sb.AppendLine(string.Format("| elapsed time:    \t {0} ms", timer.ElapsedMilliseconds));
                                            sb.AppendLine(string.Format("| equivalence cost:\t {0} ms", equivTimer.ElapsedMilliseconds));
                                            sb.AppendLine(string.Format("| membership cost: \t {0} ms", membershipTimer.ElapsedMilliseconds));
                                            sb.AppendLine(string.Format("| attempts:        \t {0}", lim));
                                            yield return(regexp);
                                        }
                                        else
                                        {
                                            Console.WriteLine("used dfa");
                                            equivTimer.Stop();
                                        }
                                    }
                                    else
                                    {
                                        membershipTimer.Stop();
                                    }
                                }
                                else
                                {
                                    membershipTimer.Stop();
                                    isSubset = false;
                                }
                            }
                            #endregion

                            //#region Subsets
                            //if (isSubset)
                            //{
                            //    foreach (var reg1 in subsetReg)
                            //    {
                            //        var union = (reg1.CompareTo(regexp) > 0) ? (new REUnion(reg1, regexp)) : (new REUnion(regexp, reg1));
                            //        visited.Add(union.ToString());
                            //        sb1 = new StringBuilder();
                            //        sb1.Append(union + " From union");
                            //        file.WriteLine(sb1);
                            //        lim++;

                            //        membershipTimer.Start();
                            //        if (CorrectOnPosSet(union, posMN) && CorrectOnPosSet(union, positive))
                            //        {
                            //            membershipTimer.Stop();

                            //            equivTimer.Start();
                            //            var rDfa = getDfa(union);
                            //            memoDfa[union.ToString()] = rDfa;

                            //            if (rDfa.IsEquivalentWith(dfa, solver))
                            //            {
                            //                equivTimer.Stop();
                            //                timer.Stop();

                            //                sb.Append("| ");
                            //                union.ToString(sb);
                            //                sb.AppendLine("|");
                            //                sb.AppendLine(string.Format("| elapsed time:    \t {0} ms", timer.ElapsedMilliseconds));
                            //                sb.AppendLine(string.Format("| equivalence cost:\t {0} ms", equivTimer.ElapsedMilliseconds));
                            //                sb.AppendLine(string.Format("| membership cost: \t {0} ms", membershipTimer.ElapsedMilliseconds));
                            //                sb.AppendLine(string.Format("| attempts:        \t {0}", lim));
                            //                yield return union;
                            //            }
                            //            else
                            //            {
                            //                Console.WriteLine("used dfa");
                            //                equivTimer.Stop();
                            //            }
                            //        }
                            //        else
                            //        {
                            //            membershipTimer.Stop();
                            //        }
                            //    }
                            //    subsetReg.Add(regexp);
                            //}
                            //#endregion
                        }
                    }

                    visited = new HashSet <string>(visited.Union(newReg));
                }
            }
        }
Example #23
0
        // 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);
        }