public static bool ApplyTemplates(HashSet <int> templates) { var commonGlobals = Minimize.FindCommonGlobals(); var ret = false; // Prune away ones that don't have constants associated with them templates = new HashSet <int>( templates.Where(t => !templateMap[t].All(tup => tup.Value.SetEquals(fileToKeepConstants[tup.Key])))); // Prune away ones that don't talk about common globals templates = new HashSet <int>( templates.Where(t => { var expr = SimplifyExpr.ToExpr(templateToStr[t]); var vu = new GlobalVarsUsed(); vu.VisitExpr(expr); return(vu.globalsUsed.IsSubsetOf(commonGlobals)); })); var newFileToProg = new Dictionary <string, PersistentProgram>(); var templateToConstants = new Dictionary <int, int>(); templates.Iter(t => templateToConstants.Add(t, 0)); foreach (var tup in fileToProg) { var program = tup.Value.getProgram(); BoogieUtil.DoModSetAnalysis(program); var globals = new HashSet <string>(program.TopLevelDeclarations.OfType <GlobalVariable>().Select(g => g.Name)); var newconstants = new HashSet <Constant>(); foreach (var t in templates) { var expr = SimplifyExpr.ToExpr(templateToStr[t]); var nonold = new GatherNonOldVariables(); nonold.VisitExpr(expr); var mustmod = new HashSet <string>(nonold.variables); mustmod.IntersectWith(globals); foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { var mod = new HashSet <string>(impl.Proc.Modifies.Select(ie => ie.Name)); if (!mustmod.IsSubsetOf(mod)) { continue; } // create new constant var nc = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "PMnewConst" + (NewConstCounter++), btype.Bool), false); nc.AddAttribute("existential"); newconstants.Add(nc); if (!templateMap[t].ContainsKey(tup.Key)) { templateMap[t].Add(tup.Key, new HashSet <string>()); } templateMap[t][tup.Key].Add(nc.Name); ret = true; templateToConstants[t]++; impl.Proc.Ensures.Add(new Ensures(false, Expr.Imp(Expr.Ident(nc), expr))); } } program.AddTopLevelDeclarations(newconstants); newFileToProg.Add(tup.Key, new PersistentProgram(program)); } fileToProg = newFileToProg; foreach (var tup in templateToConstants) { Console.WriteLine("Applying template {0}: {1} ({2} constants created)", tup.Key, templateToStr[tup.Key], tup.Value); } return(ret); }
static void Main(string[] args) { Console.CancelKeyPress += Console_CancelKeyPress; if (args.Length < 1) { Console.WriteLine("ProofMin file(s).bpl [options]"); return; } var boogieArgs = ""; var once = false; var printcontracts = false; var keepPatterns = new HashSet <string>(); var filePatterns = new HashSet <string>(); for (int i = 0; i < args.Length; i++) { if (!args[i].StartsWith("/") && args[i].EndsWith(".bpl")) { filePatterns.Add(args[i]); continue; } if (args[i].StartsWith("/files:")) { filePatterns.UnionWith( System.IO.File.ReadAllLines(args[i].Substring("/files:".Length))); continue; } if (args[i] == "/break") { System.Diagnostics.Debugger.Launch(); continue; } if (args[i] == "/once") { once = true; continue; } if (args[i] == "/noSI") { Minimize.useSI = false; Minimize.usePerf = 2.0; continue; } if (args[i] == "/dbg") { dbg = true; Minimize.dbg = true; continue; } if (args[i] == "/printAssignment") { printcontracts = true; continue; } if (args[i].StartsWith("/keep:")) { keepPatterns.Add(args[i].Substring("/keep:".Length)); continue; } if (args[i].StartsWith("/initBound:")) { InitBound = Int32.Parse(args[i].Substring("/initBound:".Length)); continue; } if (args[i] == "/perf") { Minimize.usePerf = 2.0; continue; } if (args[i] == "/cnf") { SimplifyExpr.SimplifyToCNF = true; continue; } if (args[i].StartsWith("/perf:")) { Minimize.usePerf = double.Parse(args[i].Substring("/perf:".Length)); continue; } boogieArgs += args[i] + " "; } // Initialize Boogie boogieArgs += " /typeEncoding:m /weakArrayTheory /errorLimit:1 "; Initalize(boogieArgs); // Get the input files var files = new HashSet <string>(); foreach (var fp in filePatterns) { var fname = System.IO.Path.GetFileName(fp); var dirname = System.IO.Path.GetDirectoryName(fp); if (dirname == "") { dirname = "."; } files.UnionWith(System.IO.Directory.GetFiles(dirname, fname)); } if (files.Count == 0) { Console.WriteLine("No files given"); return; } Console.WriteLine("Found {0} files", files.Count); if (once) { Debug.Assert(files.Count() == 1); RunOnce(new PersistentProgram(BoogieUtil.ReadAndResolve(files.First(), true)), printcontracts); return; } Minimize.sw.Start(); Minimize.ReadFiles(files, keepPatterns); Dictionary <int, int> templateToPerfDelta = new Dictionary <int, int>(); HashSet <int> min = new HashSet <int>(); var dropped = new HashSet <int>(); var ApplyTemplatesDone = false; do { do { Dictionary <int, int> t2d; var min2 = Minimize.FindMin(dropped, out t2d); // dropped var templates = new HashSet <int>(Minimize.templateToStr.Keys); dropped = templates.Difference(min2); // merge perf foreach (var tup in t2d) { if (!templateToPerfDelta.ContainsKey(tup.Key)) { templateToPerfDelta.Add(tup.Key, tup.Value); } else { templateToPerfDelta[tup.Key] += tup.Value; } } Console.WriteLine("Obtained minimal templates, at size {0}", min2.Count); if (min.SetEquals(min2)) { Console.WriteLine("Reached fixpoint; we're done"); break; } min = min2; Console.WriteLine("Contemplating re-running with broken down templates"); var rerun = false; Minimize.candidateToCost = new Dictionary <int, int>(); var newTemplates = new HashSet <int>(); min2.Iter(t => { var b = Minimize.PruneDisjuncts(t, ref newTemplates); rerun |= b; }); if (!rerun) { Console.WriteLine("Nothing to break; we're done"); break; } dropped.ExceptWith(newTemplates); Console.WriteLine("Rerunning Minimization"); } while (true); if (ApplyTemplatesDone) { break; } ApplyTemplatesDone = true; // compute common set of globals var rr = Minimize.ApplyTemplates(min.Difference(Minimize.priorFullyInstantiatedTemplates)); if (!rr) { break; } } while (true); foreach (var c in min) { Console.WriteLine("Template to origin info for {0} : {1}", c, Minimize.templateToStr[c]); if (!Minimize.templateToOriginExpr.ContainsKey(c) || Minimize.templateToOriginExpr[c].Count == 0) { continue; } foreach (var tup in Minimize.templateToOriginExpr[c]) { Console.WriteLine(" {0}{1}", tup.Item1 ? "{:loop} " : "", tup.Item2.ToString()); } } foreach (var c in min) { var gen = Minimize.templateToStr[c]; string ret = gen; if (Minimize.templateToOriginExpr.ContainsKey(c) && Minimize.templateToOriginExpr[c].Count != 0) { var isloop = Minimize.templateToOriginExpr[c].All(tup => tup.Item1); var exprs = Minimize.templateToOriginExpr[c].Select(tup => SimplifyExpr.ExprToTemplateSpecific(tup.Item2, isloop)); ret = exprs.First(); ret = exprs.All(s => s == ret) ? ret : gen; ret = isloop ? string.Format("{{:loop}} {0}", ret) : ret; } Console.WriteLine("Additional contract required: {0}", ret); } foreach (var tup in templateToPerfDelta) { if (tup.Value <= 2) { continue; } Console.WriteLine("Contract to pref: {0} {1}", tup.Value, Minimize.templateToStr[tup.Key]); } Console.WriteLine("Cache hits on calls to PruneAndRun: {0} / {1}", Minimize.CacheHit, Minimize.IterCnt); }