public void DileepTest1()
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            var solver = new CharSetSolver(BitWidth.BV64);
            List<char> alph = new List<char> { 'a', 'b' };
            HashSet<char> al = new HashSet<char>(alph);

            PDLPred phi = new PDLModSetEq(new PDLIndicesOf("a"), 2, 1);
            phi = new PDLAnd(new PDLStartsWith("a"), phi);
            var dfa1 = phi.GetDFA(al, solver);

            var a = solver.MkCharConstraint(false, 'a');
            var b = solver.MkCharConstraint(false, 'b');
            var moves = new List<Move<BDD>>();

            moves.Add(new Move<BDD>(0, 0, a));
            moves.Add(new Move<BDD>(0, 5, a));
            moves.Add(new Move<BDD>(5, 0, a));
            moves.Add(new Move<BDD>(5, 5, b));

            var dfa2 = Automaton<BDD>.Create(0, new int[] { 5 }, moves);
            var feedbackGrade = DFAGrading.GetGrade(dfa1, dfa2, al, solver, timeout, 10, FeedbackLevel.Solution, true, false, false);
            var feedString = "<ul>";
            foreach (var feed in feedbackGrade.Second)
                feedString += string.Format("<li>{0}</li>", feed);
            feedString += "</ul>";

            Console.Write( string.Format("<div>Grade: {0} <br /> Feedback: {1}</div>", feedbackGrade.First, feedString));
        }
        public void MyTest()
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            var solver = new CharSetSolver(BitWidth.BV64);
            List<char> alph = new List<char> { 'a', 'b' };
            HashSet<char> al = new HashSet<char>(alph);

            var a = solver.MkCharConstraint(false, 'a');
            var b = solver.MkCharConstraint(false, 'b');
            var moves = new List<Move<BDD>>();

            moves.Add(new Move<BDD>(0, 1, a));
            moves.Add(new Move<BDD>(0, 3, b));
            moves.Add(new Move<BDD>(1,2, b));
            moves.Add(new Move<BDD>(2, 1, a));
            moves.Add(new Move<BDD>(1, 1, a));
            moves.Add(new Move<BDD>(2, 2, b));

            moves.Add(new Move<BDD>(3, 4, a));
            moves.Add(new Move<BDD>(4, 3, b));
            moves.Add(new Move<BDD>(3, 3, b));
            moves.Add(new Move<BDD>(4, 4, a));

            var dfa1 = Automaton<BDD>.Create(0, new int[] { 0,1,3 }, moves).Determinize(solver).Minimize(solver);
            foreach (var v in pdlEnumerator.SynthesizePDL(al, dfa1, solver, new StringBuilder(), 5000))
            {
                Console.WriteLine(PDLUtil.ToEnglishString(v));
                break;
            }
        }
 /// <summary>
 /// Returns the minimum PDL edit distance ratio between all the PDL A1 and A2 inferred for dfa1 and dfa2
 /// in less than timeout. For every  min_ij(d(A1i,A2j)/|A1i)
 /// </summary>
 /// <param name="dfa1"></param>
 /// <param name="dfa2"></param>
 /// <param name="al"></param>
 /// <param name="solver"></param>
 /// <param name="timeout"></param>
 /// <returns></returns>
 public static double GetMinimalFormulaEditDistanceRatio(Automaton<BDD> dfa1, Automaton<BDD> dfa2, HashSet<char> al, CharSetSolver solver, long timeout, PDLEnumerator pdlEnumerator)
 {
     var v = GetMinimalFormulaEditDistanceTransformation(dfa1, dfa2, al, solver, timeout, pdlEnumerator);
     if(v!=null){
         var transformation = v.First;
         var scaling = 1.0;
         return transformation.totalCost / (transformation.minSizeForTreeA * scaling);
     }
     return 10;
 }
        private void runTest(string testName)
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            CharSetSolver solver = new CharSetSolver(BitWidth.BV64);
            var dfa_al = ReadDFA(testName, solver);

            PDLPred synthPhi = null;
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("*------------------------------------");
            sb.AppendLine("| " + testName);
            sb.AppendLine("|------------------------------------");

            foreach (var phi in pdlEnumerator.SynthesizePDL(dfa_al.First, dfa_al.Second, solver, sb, timeout))
            {
                synthPhi = phi;
                break;
            }

            sb.AppendLine("*------------------------------------");
            sb.AppendLine();

            System.Console.WriteLine(sb);
        }
        /// <summary>
        /// Find the min formula edit distance between two dfas
        /// </summary>
        /// <param name="dfa1"></param>
        /// <param name="dfa2"></param>
        /// <param name="al"></param>
        /// <param name="solver"></param>
        /// <param name="timeout"></param>
        /// <returns>transformation of smallest cost, transf of feeedback (first one)</returns>
        public static Pair<Transformation, Transformation> GetMinimalFormulaEditDistanceTransformation(Automaton<BDD> dfa1, Automaton<BDD> dfa2, HashSet<char> al, CharSetSolver solver, long timeout, PDLEnumerator pdlEnumerator)
        {
            int maxFormulas = 30;
            //Find all the formulas describing dfa1 and dfa2
            var v = new StringBuilder();
            List<PDLPred> pdlFormulae1 = new List<PDLPred>();
            foreach (var phi in pdlEnumerator.SynthesizePDL(al, dfa1, solver, v, timeout, maxFormulas))
            {
                //Console.WriteLine(phi);
                pdlFormulae1.Add(phi);
            }

            if (pdlFormulae1.Count == 0)
                return null;

            List<PDLPred> pdlFormulae2 = new List<PDLPred>();
            //Console.WriteLine();
            foreach (var phi in pdlEnumerator.SynthesizePDL(al, dfa2, solver, v, timeout, maxFormulas))
            {
                //Console.WriteLine(phi);
                pdlFormulae2.Add(phi);
            }

            if (pdlFormulae2.Count == 0)
                return null;

            // Initialize parameters for feedback search                         
            double minSizePhi1 = 20;
            PDLPred smallestPhi1 = null;
            PDLPred closestPhi2toSmallerPhi1 = null;

            //This first enumerations find the smallest phi1 describing the solution and the closest phi2 describing the solution for feedback
            foreach (var phi1 in pdlFormulae1)
            {
                var sizePhi1 = phi1.GetFormulaSize();
                if (sizePhi1 < minSizePhi1)
                {
                    minSizePhi1 = (double)sizePhi1;
                    smallestPhi1 = phi1;
                }
            }
            // Look for the closest formula to the smallest one describing phi1
            // The formula can be at most distance 2 from the smallest phi1
            double minEd = 3;
            foreach (var phi2 in pdlFormulae2)
            {
                if (!phi2.IsComplex())
                {
                    if (minEd != 1 && ((int)Math.Abs(smallestPhi1.GetFormulaSize() - phi2.GetFormulaSize())) <= minEd)
                    {
                        var tr = GetFormulaEditDistance(smallestPhi1, phi2);
                        var fed = tr.totalCost;
                        if (fed < minEd)
                        {
                            minEd = fed;
                            closestPhi2toSmallerPhi1 = phi2;
                        }
                        //if (closestPhi2toSmallerPhi1 == null || closestPhi2toSmallerPhi1.GetFormulaSize() > phi2.GetFormulaSize())
                        //    closestPhi2toSmallerPhi1 = phi2;
                        if (minEd == 0)
                            throw new PDLException("cannot be 0");
                    }
                }
            }

            //Initialize parameters for grading search
            //This second enumerations are for grading
            minEd = 100;
            minSizePhi1 = 100;
            PDLPred phiMin1 = null;
            PDLPred phiMin2 = null;

            foreach (var phi1 in pdlFormulae1)
            {
                var sizePhi1 = phi1.GetFormulaSize();
                if (sizePhi1 < minSizePhi1)
                    minSizePhi1 = (double)sizePhi1;
                foreach (var phi2 in pdlFormulae2)
                {
                    if (minEd != 1 && ((int)Math.Abs(phi1.GetFormulaSize() - phi2.GetFormulaSize())) <= minEd)
                    {
                        var tr = GetFormulaEditDistance(phi1, phi2);
                        var fed = tr.totalCost;
                        if (fed < minEd)
                        {
                            minEd = fed;
                            phiMin1 = phi1;
                            phiMin2 = phi2;
                        }
                        if (minEd == 0)
                            throw new PDLException("cannot be 0");
                    }
                }
            }
            Transformation tgrade = GetFormulaEditDistance(phiMin1, phiMin2);
            tgrade.minSizeForTreeA = minSizePhi1;
            Transformation tfeed = null;
            if (closestPhi2toSmallerPhi1 != null)
            {
                tfeed = GetFormulaEditDistance(smallestPhi1, closestPhi2toSmallerPhi1);
                tfeed.minSizeForTreeA = minSizePhi1;
            }
            return new Pair<Transformation, Transformation>(tgrade, tfeed);
        }
        public override string ToString()
        {
            long enumTimeout = 1500L;
            #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;
                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;
                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 void DileepTest1()
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            PDLPred phi = new PDLAtSet('a', new PDLPredSet("x", new PDLModSetEq(new PDLAllPosBefore(new PDLPosVar("x")), 2, 1)));

            var solver = new CharSetSolver(BitWidth.BV64);
            var alph = new List<char> { 'a', 'b' };
            var al = new HashSet<char>(alph);

            var dfa = phi.GetDFA(al, solver);

            //solver.SaveAsDot(dfa, "C:/Users/Dileep/Desktop/oddPos.dot");

            PDLPred synthPhi = null;
            StringBuilder sb = new StringBuilder();

            foreach (var phi1 in pdlEnumerator.SynthesizePDL(al, dfa, solver, sb, 10000))
            {
                synthPhi = phi1;
                break;
            }

            Console.WriteLine(sb);

        }
        public void DileepTest()
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            PDLPred phi = new PDLIntGeq(new PDLIndicesOf("ab"), 2);

            var solver = new CharSetSolver(BitWidth.BV64);
            var alph = new List<char> { 'a', 'b' };
            var al = new HashSet<char>(alph);

            var dfa = phi.GetDFA(al, solver);

            PDLPred synthPhi = null;
            StringBuilder sb = new StringBuilder();

            foreach (var phi1 in pdlEnumerator.SynthesizePDL(al, dfa, solver, sb, 10000))
            {
                synthPhi = phi1;
                break;
            }

            Console.WriteLine(sb);

        }
        //
        private void runUnderapproxTest(string testName)
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();
            int printLimit = 10;

            CharSetSolver solver = new CharSetSolver(BitWidth.BV64);
            var dfa_al = ReadDFA(testName, solver);
            //PrintDFA(dfa_al.Second, "A", dfa_al.First);

            StringBuilder sb = new StringBuilder();

            int i = 0;
            foreach (var pair in pdlEnumerator.SynthesizeUnderapproximationPDL(dfa_al.First, dfa_al.Second, solver, sb, timeout))
            {
                i++;
                pair.First.ToString(sb);
                sb.AppendLine(" ### +"+pair.Second.ToString()+" ### +"+pair.First.GetFormulaSize());
                sb.AppendLine();
                if (i == printLimit)
                    break;
            }

            System.Console.WriteLine(sb);
        }
        /// <summary>
        /// Computes the grade for attempt using all the possible metrics
        /// </summary>
        /// <param name="dfaGoal">minimal correct dfa</param>
        /// <param name="dfaAttempt">dfa to be graded</param>
        /// <param name="al">input alphabet</param>
        /// <param name="solver">SMT solver for char set</param>
        /// <param name="timeout">timeout for the PDL enumeration (suggested > 1000)</param>
        /// <param name="maxGrade">Max grade for the homework</param>        
        /// <param name="enableDFAED">true to enable DFA edit distance</param>
        /// <param name="enablePDLED">true to enable PDL edit distance</param>
        /// <param name="enableDensity">true to enable density distance</param>
        /// <returns>Grade for dfa2</returns>
        public static Pair<int, IEnumerable<DFAFeedback>> GetGrade(
            Automaton<BDD> dfaGoal, Automaton<BDD> dfaAttempt, HashSet<char> al,
            CharSetSolver solver, long timeout,
            int maxGrade, FeedbackLevel level,
            bool enableDFAED, bool enablePDLED, bool enableDensity)
        {
            PDLEnumerator pdlEnumerator = new PDLEnumerator();

            var feedList = new List<DFAFeedback>();

            DFAFeedback defaultFeedback = new StringFeedback(level, StringFeedbackType.Wrong, al, solver);

            #region Accessory and initial vars
            //Compute minimized version of DFAs
            var dfaGoalMin = dfaGoal.Determinize(solver).Minimize(solver);
            var dfaAttemptMin = dfaAttempt.Determinize(solver).Minimize(solver);

            //Initialize distances at high values in case they are not used
            // they only produce positive grade if between 0 and 1
            double pdlEditDistanceScaled = 2;
            double densityRatio = 2;
            double dfaED = 2;
            #endregion

            #region deductions on the grade based on the size of the dfa
            //Deduction if DFA is smaller than it should be: used only for PDL ed and for density
            var smallerDFADeduction = 0.2 * Math.Sqrt(
                        Math.Max(0.0, dfaGoalMin.StateCount - dfaAttemptMin.StateCount) /
                        ((double)dfaGoalMin.StateCount));
            #endregion

            #region check whether the attempt is equivalent to the solution
            if (dfaGoal.IsEquivalentWith(dfaAttempt, solver))
            {
                Console.WriteLine("Correct");
                feedList.Add(new StringFeedback(level, StringFeedbackType.Correct, al, solver));
                return new Pair<int, IEnumerable<DFAFeedback>>(maxGrade, feedList);
            }
            #endregion

            #region metrics computation
            Stopwatch swPDLed = new Stopwatch();
            swPDLed.Start();
            #region PDL edit distance
            Transformation feedbackTransformation = null;
            if (enablePDLED)
            {
                var trpair = PDLEditDistance.GetMinimalFormulaEditDistanceTransformation(dfaGoalMin, dfaAttemptMin, al, solver, timeout, pdlEnumerator);

                if (trpair != null)
                {
                    var transformationGrade = trpair.First;
                    feedbackTransformation = trpair.Second;
                    var scaling = 1.0;
                    pdlEditDistanceScaled = transformationGrade.totalCost / (transformationGrade.minSizeForTreeA * scaling) + smallerDFADeduction;
                }
            }
            #endregion
            swPDLed.Stop();

            Stopwatch swDensity = new Stopwatch();
            swDensity.Start();
            #region density distance
            if (enableDensity)
            {
                densityRatio = DFADensity.GetDFADifferenceRatio(dfaGoalMin, dfaAttemptMin, al, solver);
                densityRatio += smallerDFADeduction;
            }
            #endregion
            swDensity.Stop();

            Stopwatch swDFAed = new Stopwatch();
            swDFAed.Start();
            #region DFA edit distance
            DFAEditScript dfaEditScript = null;
            if (enableDFAED)
            {
                //limit the depth of the DFA edit distance search
                var maxMoves = Math.Max(1, 6 - (int)Math.Sqrt(dfaAttempt.MoveCount + dfaAttempt.StateCount));
                dfaEditScript = DFAEditDistance.GetDFAOptimalEdit(dfaGoal, dfaAttempt, al, solver, timeout, new StringBuilder());

                if (dfaEditScript != null)
                    dfaED = ((double)(dfaEditScript.GetCost())) / ((double)((dfaGoalMin.StateCount + 1) * al.Count));

            }
            #endregion
            swDFAed.Stop();

            #endregion

            #region metrics scaling
            var scalingSquarePDLED = 1.005;
            var scalingSquareDensity = 1; var multv2 = 0.5;
            var scalingSquareDFAED = 1.03;

            var scaledPdlED = (0.9 * (scalingSquarePDLED + pdlEditDistanceScaled) * (scalingSquarePDLED + pdlEditDistanceScaled)) - scalingSquarePDLED * scalingSquarePDLED;
            var scaledDensityRatio = (scalingSquareDensity + (multv2 * densityRatio)) * (scalingSquareDensity + (multv2 * densityRatio)) - scalingSquareDensity * scalingSquareDensity;
            var scaledDfaED = (scalingSquareDFAED + dfaED) * (scalingSquareDFAED + dfaED) - scalingSquareDFAED * scalingSquareDFAED;


            //Select dominating Feedback based on grade
            double unscaledGrade = Math.Min(Math.Min(scaledPdlED, scaledDensityRatio), scaledDfaED);
            var pdledwins = scaledPdlED <= Math.Min(scaledDensityRatio, scaledDfaED);
            var dfaedwins = scaledDfaED <= Math.Min(scaledDensityRatio, scaledPdlED);
            var densitywins = scaledDensityRatio <= Math.Min(scaledDfaED, scaledPdlED);
            #endregion

            #region Feedback Selection
            if (pdledwins && feedbackTransformation != null && feedbackTransformation.pdlB.GetFormulaSize()<10)
                feedList.Add(new PDLEDFeedback(level, al, feedbackTransformation, scaledPdlED, solver));

            if ((dfaedwins || feedList.Count == 0) && dfaEditScript != null && !dfaEditScript.IsComplex())
            {
                feedList = new List<DFAFeedback>();
                feedList.Add(new DFAEDFeedback(dfaGoal, dfaAttempt, level, al, dfaEditScript, scaledDfaED, solver));
            }

            if (densitywins || feedList.Count == 0)
            {
                feedList = new List<DFAFeedback>();
                feedList.Add(new DensityFeedback(level, al, dfaGoal, dfaAttempt, scaledDensityRatio, solver));
            }

            if (feedList.Count == 0)
            {
                Console.WriteLine("Why no feedback!!");
                feedList.Add(defaultFeedback);
            }
            #endregion           

            #region normalize grade
            var scaledGrade = maxGrade - (int)Math.Round(unscaledGrade * (double)(maxGrade));
            //If rounding yields maxgrade deduct 1 point by default
            if (scaledGrade == maxGrade)
                scaledGrade = maxGrade - 1;

            //Remove possible deduction
            scaledGrade = scaledGrade < 0 ? 0 : scaledGrade;
            return new Pair<int, IEnumerable<DFAFeedback>>(scaledGrade, feedList);
            #endregion
        }