Exemple #1
0
        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);
        }
Exemple #2
0
        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));
                    }
                }
            }
        }
Exemple #3
0
        // 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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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));
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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);
        }