static void XML(params int[] indices)
 {
     if (indices.Length == 0)
     {
         foreach (WExpr program in programs)
         {
             string   s1            = program.ToString();
             XElement xml           = new XElement("WhileProgram", new XAttribute("NumVariables", program.GetNumVariables()), program.ToXML());
             WExpr    parsedProgram = WhileUtilities.ParseWhileProgramFromXML(xml);
             string   s2            = parsedProgram.ToString();
             Console.WriteLine(s1 == s2);
         }
     }
     else
     {
         foreach (int index in indices)
         {
             WExpr    program       = programs[index];
             string   s1            = program.ToString();
             XElement xml           = new XElement("WhileProgram", new XAttribute("NumVariables", program.GetNumVariables()), program.ToXML());
             WExpr    parsedProgram = WhileUtilities.ParseWhileProgramFromXML(xml);
             string   s2            = parsedProgram.ToString();
             Console.WriteLine(s1 == s2);
         }
     }
 }
        public static Tuple <int, List <string>, string> FeedbackForWhileToTM <S>(WExpr correctProgram, TMCB <int, S> attemptTM, int maxGrade)
        {
            //returns grade, feedback strings, and a sample input for the tape simulator
            TMCB <int, int> correctTM      = correctProgram.ToTMCB(-1);
            int             numTapes       = correctProgram.GetNumVariables();
            const int       numInputs      = 100;
            const int       maxWrongOutpus = 5; //max number of wrong outputs the user is shown.

            //<correctTM> and <attemptTM> are compared by running both on a set of test inputs and comparing the outputs.
            int           inputsPerTape   = (int)Math.Pow(numInputs, (double)1 / numTapes);
            List <string> wrongOutputList = new List <string>();
            string        sampleInput     = "";

            int  countCorrectOutputs = 0;
            int  countWrongOutpus    = 0;
            bool dummy;

            foreach (int[][] input in WhileUtilities.NonNegIntTestInputs(numTapes, inputsPerTape, correctProgram.GetUselessVariables().ToArray()))
            {
                int[][] correctOutput = correctTM.Run(input, out dummy);

                //<correctTM> uses LSBF encoding, <attemptTM> uses MSBF encoding. Reverse <input> for <attemptTM>.
                for (int i = 0; i < input.Length; ++i)
                {
                    input[i] = input[i].Reverse().ToArray();
                }

                int[][] attemptOutput = attemptTM.Run(input, out dummy);

                //for comparing the outputs, reverse <correctOutput>
                for (int i = 0; i < correctOutput.Length; ++i)
                {
                    correctOutput[i] = correctOutput[i].Reverse().ToArray();
                }

                //get string representations of the outputs
                string[] correctStrings = Array.ConvertAll(correctOutput, tape => WhileUtilities.TapeToString(tape, correctTM.blank, new[] { 0 }, "_"));
                string[] attemptStrings = Array.ConvertAll(attemptOutput, tape => WhileUtilities.TapeToString(tape, attemptTM.blank, new[] { 0 }, "_"));

                if (WhileUtilities.TapesEqual(correctStrings, attemptStrings))
                {
                    ++countCorrectOutputs;
                }
                else
                {
                    if (countWrongOutpus == 0)
                    {
                        //first wrong output: corresponding input is stored in <sampleInput>
                        string[] tapes = Array.ConvertAll(input, tape => WhileUtilities.TapeToString(tape, correctTM.blank, new[] { 0 }, "_"));
                        sampleInput = string.Join(",", tapes);
                    }
                    ++countWrongOutpus;
                    if (countWrongOutpus <= maxWrongOutpus)
                    {
                        wrongOutputList.Add(string.Empty);
                        wrongOutputList.Add($"Input #{countWrongOutpus}:");
                        for (int i = 0; i < input.Length; ++i)
                        {
                            wrongOutputList.Add($"tape {i}: {WhileUtilities.TapeToString(input[i], correctTM.blank, null)}");
                        }
                        wrongOutputList.Add("Your output:");
                        for (int i = 0; i < attemptStrings.Length; ++i)
                        {
                            wrongOutputList.Add($"tape {i}: {attemptStrings[i]}");
                        }
                        wrongOutputList.Add("Correct output:");
                        for (int i = 0; i < correctStrings.Length; ++i)
                        {
                            wrongOutputList.Add($"tape {i}: {correctStrings[i]}");
                        }
                    }
                }
            }

            double        actualInputs = Math.Pow(inputsPerTape, numTapes);
            int           grade        = (int)((countCorrectOutputs / actualInputs) * maxGrade);
            List <string> feedbackList = new List <string>();

            if (countWrongOutpus == 0)
            {
                feedbackList.Add("Correct!");
            }
            else
            {
                if (countWrongOutpus <= maxWrongOutpus)
                {
                    feedbackList.Add($"{countWrongOutpus} of {actualInputs} outpus were wrong:");
                }
                else
                {
                    feedbackList.Add($"{countWrongOutpus} of {actualInputs} outpus were wrong. Here are {maxWrongOutpus} of them:");
                }
                foreach (string line in wrongOutputList)
                {
                    feedbackList.Add(line);
                }
            }

            return(new Tuple <int, List <string>, string>(grade, feedbackList, sampleInput));
        }