/// <summary> /// - runs the state machine pointed to by CurrIndex, in place, and /// returns the successor wrapped into a curr /// - assigns to argument a clone (!) of the old curr, and advances /// its choice vector and currIndex, as appropriate /// So curr points to new memory after calling Execute. The returned /// successor is stored in old memory. /// </summary> /// <param name="curr"></param> /// <returns></returns> static BacktrackingState Execute(BacktrackingState curr) { /// create a copy of curr var origState = (StateImpl)curr.State.Clone(); /// --PL Q: set as 0 every time is called? int choiceIndex = 0; /// curr.State.UserBooleanChoice is a pointer to a function with /// signature f: {} -> Bool. /// The following assigns the code under 'delegate' to this function pointer. /// curr and choiceIndex are global variables. -- PL: Q: global variables? curr.State.UserBooleanChoice = delegate() { if (choiceIndex < curr.ChoiceVector.Count) { return(curr.ChoiceVector[choiceIndex++]); } choiceIndex++; curr.ChoiceVector.Add(false); return(false); }; /// --PL: Execute the machine with index = CurrIndex curr.State.EnabledMachines[curr.CurrIndex].PrtRunStateMachine(); Debug.Assert(choiceIndex == curr.ChoiceVector.Count); /// flip last choice -- PL Q: What does this mean?? /// remove all 1's from the right while (curr.ChoiceVector.Count > 0 && curr.ChoiceVector[curr.ChoiceVector.Count - 1]) { curr.ChoiceVector.RemoveAt(curr.ChoiceVector.Count - 1); } if (curr.ChoiceVector.Count > 0) { curr.ChoiceVector[curr.ChoiceVector.Count - 1] = true; } /// --PL: create the successor var succ = new BacktrackingState(curr.State) { depth = curr.depth + 1 }; curr.State = origState; // a clone of curr.State if (curr.ChoiceVector.Count == 0) { curr.CurrIndex++; // first iterate through all choices. When exhausted, step to the next enabled machine } return(succ); }
/// <summary> /// --PL: Queue-unbounded exploration, in DFS mode /// </summary> /// <param name="queueAbstraction">Abstracting queue or not, default is not (set param as false)</param> public static void Dfs(bool queueAbstraction = false) { /// currently, we only implemented the exploration based on state hashing if (!useStateHashing) { throw new NotImplementedException(); } Console.WriteLine("Using " + (PrtEventBuffer.k == 0 ? "unbounded queue" : "queue bound of " + PrtEventBuffer.k.ToString())); /// Throw away states obtained from last rounds as all of them are static variables concretesInHash.Clear(); abstractsInHash.Clear(); abstractSuccsInHash.Clear(); #if DEBUG int max_queue_size = 0; int max_stack_size = 0; #endif /// --PL: dump states & transitions to files StreamWriter concretesFile = null; StreamWriter abstractsFile = null; StreamWriter abstractSuccsFile = null; StreamWriter transitionsFile = null; if (fileDump) { /// add "0" for name formating var suffix = (PrtEventBuffer.k < 10 ? "0" : "") + PrtEventBuffer.k.ToString(); concretesFile = new StreamWriter(Constants.dumpFileConcretePrefix + suffix + Constants.dumpFileExtension); abstractsFile = new StreamWriter(Constants.dumpFileAbstractPrefix + suffix + Constants.dumpFileExtension); abstractSuccsFile = new StreamWriter(Constants.dumpFileAbstractSuccPrefix + suffix + Constants.dumpFileExtension); transitionsFile = new StreamWriter(Constants.dumpFileTransitionPrefix + suffix + Constants.dumpFileExtension); } Debug.Assert(start != null); var startClone = (StateImpl)start.Clone(); // we need a fresh clone in each iteration (k) of Dfs /// worklist, implemented using stack var worklist = new Stack <BacktrackingState>(); // TODO: the following piece of code is duplicate. Need to refine it. worklist.Push(new BacktrackingState(startClone)); var startHash = startClone.GetHashCode(); concretesInHash.Add(startHash); if (fileDump) { concretesFile.Write(startClone.ToPrettyString()); concretesFile.WriteLine(Constants.consoleSeparator); transitionsFile.WriteLine(startHash); } if (queueAbstraction) { var startAbstract = (StateImpl)start.Clone(); startAbstract.AbstractMe(); // abstract queue abstractsInHash.Add(startAbstract.GetHashCode()); /// compute abstract succs right way startAbstract.CollectAbstractSuccessors(abstractSuccsInHash, abstractSuccsFile); if (fileDump) { abstractsFile.Write(startAbstract.ToPrettyString()); abstractsFile.WriteLine(Constants.consoleSeparator); } } /// the main loop of DFS while (worklist.Count != 0) /// if worklist is not empty { #if false // code for investigating memory usage if (worklist.Count == 5000) { Console.WriteLine("Stack depth of 5000 reached"); GC.Collect(); var mem1 = GC.GetTotalMemory(true) / (1024.0 * 1024.0); Console.WriteLine("Current memory usage = {0} MB", mem1.ToString("F2")); // lets clone var stackarr = worklist.ToArray(); var newStack = new List <StateImpl>(); for (int i = 0; i < stackarr.Length; i++) { newStack.Add((StateImpl)stackarr[i].State.Clone()); } GC.Collect(); var mem2 = GC.GetTotalMemory(true) / (1024.0 * 1024.0); Console.WriteLine("Memory usage after cloning the stack = {0} MB", mem2.ToString("F2")); Console.WriteLine("Average usage per state = {0} MB", (mem2 - mem1) / 5000.0); Environment.Exit(0); } #endif /// -PL: pop a state from worklist, and operate on it var curr = worklist.Pop(); if (curr.CurrIndex >= curr.State.EnabledMachines.Count) // if "done" with curr { continue; } /// Get a successor by executing the enabled machine pointed to by currIndex. /// Also, advance currIndex and/or choiceIndex and push curr state back to worklist /// TODO: try BFS BacktrackingState succ = Execute(curr); worklist.Push(curr); // CurrIndex of curr has been updated // if we are in competitor finding mode if (StateImpl.mode == StateImpl.ExploreMode.Competitor) { CheckPredHash(curr.State, succ.State); } /// check for failure before adding new state: may fail due /// to failed assume, in which case we don't want to add if (!succ.State.CheckFailure(succ.depth)) { // update concrete state hashset var succHash = succ.State.GetHashCode(); if (!concretesInHash.Add(succHash)) // -- PL: if successor has been explored { continue; } if (!succ.State.CheckConcreteStateInvariant()) { throw new QuTLException("QuTL formula fails in concete model checking!"); } worklist.Push(succ); #if DEBUG max_stack_size = Math.Max(max_stack_size, worklist.Count); #endif if (fileDump) { concretesFile.Write(succ.State.ToPrettyString()); // + " = " + succHash.ToPrettyString()); concretesFile.WriteLine(Constants.consoleSeparator); transitionsFile.WriteLine("{0} -> {1}", curr.State.GetHashCode(), succHash); } if (queueAbstraction) { var succAbs = (StateImpl)succ.State.Clone(); succAbs.AbstractMe(); var succAbsHash = succAbs.GetHashCode(); #if false #region dirty code, debugging============================ var currAbs = (StateImpl)curr.State.Clone(); currAbs.AbstractMe(); if (currAbs.GetHashCode() == -105414283) { Console.WriteLine("%%%%%%%%%%%%%%%%%%% = beginning ========"); Console.WriteLine(curr.State.ToPrettyString()); Console.WriteLine(); Console.WriteLine(currAbs.ToPrettyString()); Console.WriteLine(succ.State.ToPrettyString()); Console.WriteLine("%%%%%%%%%%%%%%%%%%% = " + succAbsHash); Console.WriteLine(succAbs.ToPrettyString()); Console.WriteLine("Abstract Successors............"); } #endregion #endif if (abstractsInHash.Add(succAbsHash)) /// --PL: if the abstract of current state has NOT been explored { succAbs.CollectAbstractSuccessors(abstractSuccsInHash, abstractSuccsFile); if (fileDump) { abstractsFile.Write(succAbs.ToPrettyString()); abstractsFile.WriteLine(Constants.consoleSeparator); } } #if false if (currAbs.GetHashCode() == -417525807) { Environment.Exit(0); } #endif } #if DEBUG // status and diagnostics if (concretesInHash.Count % 1000 == 0) { Console.WriteLine("-------------- Number of concrete states visited so far = {0}", concretesInHash.Count); if (queueAbstraction) { Console.WriteLine("-------------- Number of abstract states found so far = {0}", abstractsInHash.Count); Console.WriteLine("-------------- Number of abstract successors found so far = {0}{1}", abstractSuccsInHash.Count, StateImpl.invariant ? " (only those satisfying all static invariants)" : ""); } Console.WriteLine("-------------- Maximum queue size encountered so far = {0}", max_queue_size); Console.WriteLine("-------------- Maximum stack size encountered so far = {0}", max_stack_size); Console.WriteLine(); } // update maximum encountered queue size foreach (PrtImplMachine m in succ.State.ImplMachines) { max_queue_size = Math.Max(max_queue_size, m.eventQueue.Size()); } #endif } } // end of while loop Console.WriteLine(""); Console.WriteLine("Number of concrete states visited = {0}", concretesInHash.Count); if (queueAbstraction) { Console.WriteLine("Number of abstract states encountered = {0}", abstractsInHash.Count); Console.WriteLine("Number of abstract successors found = {0}{1}", abstractSuccsInHash.Count, StateImpl.invariant ? " (only those satisfying all static invariants)" : ""); } #if DEBUG Console.WriteLine("Maximum queue size encountered = {0}", max_queue_size); Console.WriteLine("Maximum stack size encountered = {0}", max_stack_size); #endif Console.WriteLine(); if (fileDump) { /// flush streams before close them concretesFile.Flush(); abstractsFile.Flush(); abstractSuccsFile.Flush(); transitionsFile.Flush(); /// close streams concretesFile.Close(); abstractsFile.Close(); abstractSuccsFile.Close(); transitionsFile.Close(); } }