public static Expr Simplify(Expr e) { var vs = new SimplifyExpr(); var e1 = vs.VisitExpr(e); var e2 = SimplifyToCNF ? Expr.And(MakeCNF(e1)) : e1; var e3 = NormalizeExpr(e2); return(e3); }
public static void ReadFiles(IEnumerable <string> files, HashSet <string> keepPatterns) { foreach (var f in files) { Program program; try { program = BoogieUtil.ReadAndResolve(f); } catch (cba.Util.InvalidProg) { continue; } CheckRMT(program); fileToKeepConstants.Add(f, new HashSet <string>()); // Add annotations foreach (var p in keepPatterns) { var re = new Regex(p); program.TopLevelDeclarations.OfType <Constant>() .Where(c => QKeyValue.FindBoolAttribute(c.Attributes, "existential") && re.IsMatch(c.Name)) .Iter(c => { c.AddAttribute(Driver.MustKeepAttr); fileToKeepConstants[f].Add(c.Name); }); } // Prune, according to annotations DropConstants(program, new HashSet <string>( program.TopLevelDeclarations.OfType <Constant>() .Where(c => QKeyValue.FindBoolAttribute(c.Attributes, Driver.DropAttr)) .Select(c => c.Name))); var allconstants = new Dictionary <string, Constant>(); program.TopLevelDeclarations.OfType <Constant>() .Where(c => QKeyValue.FindBoolAttribute(c.Attributes, "existential")) .Iter(c => allconstants.Add(c.Name, c)); // Normalize expressions if (!SimplifyExpr.SimplifyToCNF) { program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Proc.Ensures.Iter(ens => SimplifyExpr.SimplifyEnsures(ens, allconstants))); } else { var constants = new HashSet <string>(allconstants.Keys); program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Proc.Ensures = SimplifyExpr.SimplifyEnsures(impl.Proc.Ensures, allconstants)); allconstants.Where(tup => !constants.Contains(tup.Key)) .Iter(tup => program.AddTopLevelDeclaration(tup.Value)); } // Remove constants that don't hold -- optimization HashSet <string> consts = new HashSet <string>(allconstants.Keys); HashSet <string> assignment; int perf = 0; if (Driver.InitBound > 0) { perf = Driver.InitBound; } var ret = PruneAndRun(new PersistentProgram(program), consts, out assignment, ref perf); if (ret != BoogieVerify.ReturnStatus.OK) { Console.WriteLine("Warning: Program {0} doesn't have an initial inductive proof", f); continue; } // anything not in assignment can be dropped DropConstants(program, consts.Difference(assignment)); consts.Difference(assignment).Iter(s => allconstants.Remove(s)); fileToKeepConstants[f].IntersectWith(assignment); Console.WriteLine("File {0} defines {1} constants ({2} dropped)", f, assignment.Count, consts.Count - assignment.Count); // initial perf fileToPerf.Add(f, perf); // create template map foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { foreach (var ens in impl.Proc.Ensures.Where(e => !e.Free)) { string constantName = null; Expr expr = null; var isloop = QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "LoopProcedure"); var match = Microsoft.Boogie.Houdini.Houdini.GetCandidateWithoutConstant( ens.Condition, allconstants.Keys, out constantName, out expr); if (!match) { continue; } if (fileToKeepConstants[f].Contains(constantName)) { continue; } var priorTemplateId = QKeyValue.FindIntAttribute(ens.Attributes, "template", -1); var temp = SimplifyExpr.ExprToTemplateGeneral(expr); if (strToTemplate.ContainsKey(temp)) { // template for it exists addTemplate(strToTemplate[temp], f, constantName, Tuple.Create(isloop, expr)); } else { // create new template strToTemplate.Add(temp, TemplateCounterStart + strToTemplate.Count); addTemplate(strToTemplate[temp], f, constantName, Tuple.Create(isloop, expr)); } if (priorTemplateId != -1) { priorFullyInstantiatedTemplates.Add(strToTemplate[temp]); } } } // stash the program fileToProg.Add(f, new PersistentProgram(program)); } templateToStr = new Dictionary <int, string>(); strToTemplate.Iter(tup => templateToStr.Add(tup.Value, tup.Key)); Console.WriteLine("Found {0} templates", templateMap.Count); if (dbg) { foreach (var tup in templateMap) { Console.WriteLine("Template {0} :: {1}", tup.Key, templateToStr[tup.Key]); foreach (var tup2 in tup.Value) { Console.WriteLine(" File {0}", tup2.Key); tup2.Value.Iter(c => Console.WriteLine(" Candidate {0}", c)); } } } }
// minimize disjunctions in the templates // Returns true if new constants were created // Add new templates (and existing ones for which new constants were created) to newTemplates public static bool PruneDisjuncts(int template, ref HashSet <int> newTemplates) { Console.WriteLine("Breaking down template {0}: {1}", template, templateToStr[template]); var newConstantsCreated = false; var files = new HashSet <string>(fileToProg.Keys); foreach (var file in files) { if (!templateMap[template].ContainsKey(file)) { continue; } var constants = templateMap[template][file].Difference(fileToKeepConstants[file]); if (constants.Count == 0) { continue; } var program = fileToProg[file].getProgram(); var newconstants = new List <Constant>(); foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { var newEnsures = new List <Ensures>(); foreach (var ens in impl.Proc.Ensures.Where(e => !e.Free)) { string constantName = null; Expr expr = null; var isloop = QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "LoopProcedure"); var match = Microsoft.Boogie.Houdini.Houdini.GetCandidateWithoutConstant( ens.Condition, constants, out constantName, out expr); if (!match) { continue; } var disjuncts = SimplifyExpr.GetExprDisjuncts(expr); if (disjuncts.Count == 1) { continue; } var pow = SimplifyExpr.GetPowSetDisjunctions(disjuncts); foreach (var d in pow) { var conjuncts = SimplifyExpr.GetExprConjunctions(d); foreach (var c in conjuncts) { var nc = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "PMnewConst" + (NewConstCounter++), btype.Bool), false); nc.AddAttribute("existential"); newconstants.Add(nc); templateMap[template][file].Add(nc.Name); //Console.WriteLine(" New constant created: {0}", nc.Name); newConstantsCreated = true; var e = Expr.Imp(Expr.Ident(nc), c); newEnsures.Add(new Ensures(false, e)); // Add template var temp = SimplifyExpr.ExprToTemplateGeneral(c); if (strToTemplate.ContainsKey(temp)) { // template for it exists addTemplate(strToTemplate[temp], file, nc.Name, Tuple.Create(isloop, c)); } else { // create new template int v = TemplateCounterStart + strToTemplate.Count; strToTemplate.Add(temp, v); templateToStr.Add(v, temp); addTemplate(strToTemplate[temp], file, nc.Name, Tuple.Create(isloop, c)); } if (!candidateToCost.ContainsKey(strToTemplate[temp])) { candidateToCost.Add(strToTemplate[temp], conjuncts.Count > 1 ? disjuncts.Count : disjuncts.Count - SimplifyExpr.GetExprDisjuncts(d).Count); } Console.WriteLine(" Template revived or created {0} :: {1} (cost = {2})", strToTemplate[temp], temp, candidateToCost[strToTemplate[temp]]); newTemplates.Add(strToTemplate[temp]); } } } impl.Proc.Ensures.AddRange(newEnsures); } program.AddTopLevelDeclarations(newconstants); fileToProg[file] = new PersistentProgram(program); } return(newConstantsCreated); }
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); }
public static Program InjectDualityProof(Program program, string DualityProofFile) { Program DualityProof; using (var st = new System.IO.StreamReader(DualityProofFile)) { var s = ParserHelper.Fill(st, new List <string>()); // replace %i by bound_var_i for (int i = 1; i <= 9; i++) { s = s.Replace(string.Format("%{0}", i), string.Format("pm_bv_{0}", i)); } var v = Parser.Parse(s, DualityProofFile, out DualityProof); if (v != 0) { throw new Exception("Failed to parse " + DualityProofFile); } } var implToContracts = new Dictionary <string, List <Expr> >(); foreach (var proc in DualityProof.TopLevelDeclarations.OfType <Procedure>()) { implToContracts.Add(proc.Name, new List <Expr>()); foreach (var ens in proc.Ensures) { implToContracts[proc.Name].AddRange(SimplifyExpr.GetExprConjunctions(ens.Condition)); } } var counter = 0; var GetExistentialConstant = new Func <Constant>(() => { var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "DualityProofConst" + (counter++), Microsoft.Boogie.Type.Bool), false); c.AddAttribute("existential"); return(c); }); var constsToAdd = new List <Declaration>(); foreach (var proc in program.TopLevelDeclarations.OfType <Procedure>()) { if (!implToContracts.ContainsKey(proc.Name)) { continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "nohoudini")) { continue; } foreach (var expr in implToContracts[proc.Name]) { var c = GetExistentialConstant(); constsToAdd.Add(c); proc.Ensures.Add(new Ensures(false, Expr.Imp(Expr.Ident(c), expr))); } } program.AddTopLevelDeclarations(constsToAdd); return(BoogieUtil.ReResolveInMem(program)); }
static HashSet <string> BreakDownInvariants(Program program, HashSet <string> candidates) { var markkeep = new HashSet <string>(); var added = new HashSet <Constant>(); var counter = 0; var GetExistentialConstant = new Func <Constant>(() => { var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "DualityProofConstBrokenDown" + (counter++), Microsoft.Boogie.Type.Bool), false); c.AddAttribute("existential"); return(c); }); var constants = new Dictionary <string, Constant>(); program.TopLevelDeclarations.OfType <Constant>() .Where(c => QKeyValue.FindBoolAttribute(c.Attributes, "existential")) .Iter(c => constants.Add(c.Name, c)); foreach (var proc in program.TopLevelDeclarations.OfType <Procedure>()) { var newens = new List <Ensures>(); foreach (var ens in proc.Ensures.Where(e => !e.Free)) { string constantName = null; Expr expr = null; var match = Microsoft.Boogie.Houdini.Houdini.GetCandidateWithoutConstant( ens.Condition, candidates, out constantName, out expr); if (!match) { continue; } var elements = SimplifyExpr.BreakDownExpr(expr); if (elements.Count == 1) { markkeep.Add(constantName); continue; } // add cost constants[constantName].AddAttribute(Driver.CostAttr, Expr.Literal(1)); // add the constituents foreach (var elem in elements) { var c = GetExistentialConstant(); added.Add(c); newens.Add(new Ensures(false, Expr.Imp(Expr.Ident(c), elem))); } } proc.Ensures.AddRange(newens); } program.TopLevelDeclarations.OfType <Constant>() .Where(c => markkeep.Contains(c.Name)) .Iter(c => c.AddAttribute(Driver.MustKeepAttr)); program.AddTopLevelDeclarations(added); return(markkeep); }
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); }