/Source/Houdini/AbstractHoudini.cs
C# | 4609 lines | 3666 code | 693 blank | 250 comment | 715 complexity | e5add6417232b0ae9b3a8eaaf32279ed MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Microsoft.Boogie;
- using Microsoft.Boogie.VCExprAST;
- using VC;
- using Outcome = VC.VCGen.Outcome;
- using Bpl = Microsoft.Boogie;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using Microsoft.Boogie.GraphUtil;
-
- namespace Microsoft.Boogie.Houdini {
-
- public class AbsHoudini
- {
- Dictionary<string, Function> existentialFunctions;
- Program program;
- Dictionary<string, Implementation> name2Impl;
- Dictionary<string, VCExpr> impl2VC;
- Dictionary<string, List<Tuple<string, Function, NAryExpr>>> impl2FuncCalls;
- // constant -> the naryexpr that it replaced
- Dictionary<string, NAryExpr> constant2FuncCall;
-
- // function -> its abstract value
- Dictionary<string, IAbstractDomain> function2Value;
-
- // impl -> functions assumed/asserted
- Dictionary<string, HashSet<string>> impl2functionsAsserted, impl2functionsAssumed;
-
- // funtions -> impls where assumed/asserted
- Dictionary<string, HashSet<string>> function2implAssumed, function2implAsserted;
-
- // impl -> handler, collector
- Dictionary<string, Tuple<ProverInterface.ErrorHandler, AbsHoudiniCounterexampleCollector>> impl2ErrorHandler;
-
- // Essentials: VCGen, Prover
- VCGen vcgen;
- ProverInterface prover;
-
- // Stats
- TimeSpan proverTime;
- int numProverQueries;
-
- public AbsHoudini(Program program, IAbstractDomain defaultElem)
- {
- this.program = program;
- this.impl2VC = new Dictionary<string, VCExpr>();
- this.impl2FuncCalls = new Dictionary<string, List<Tuple<string, Function, NAryExpr>>>();
- this.existentialFunctions = new Dictionary<string, Function>();
- this.name2Impl = new Dictionary<string, Implementation>();
- this.impl2functionsAsserted = new Dictionary<string, HashSet<string>>();
- this.impl2functionsAssumed = new Dictionary<string, HashSet<string>>();
- this.function2implAsserted = new Dictionary<string, HashSet<string>>();
- this.function2implAssumed = new Dictionary<string, HashSet<string>>();
- this.impl2ErrorHandler = new Dictionary<string, Tuple<ProverInterface.ErrorHandler, AbsHoudiniCounterexampleCollector>>();
- this.constant2FuncCall = new Dictionary<string, NAryExpr>();
-
- // Find the existential functions
- foreach (var func in program.Functions
- .Where(f => QKeyValue.FindBoolAttribute(f.Attributes, "existential")))
- existentialFunctions.Add(func.Name, func);
-
- this.function2Value = new Dictionary<string, IAbstractDomain>();
- foreach (var func in existentialFunctions.Values)
- {
- // Find if the function wishes to use a specific abstract domain
- var domain = QKeyValue.FindStringAttribute(func.Attributes, "absdomain");
- if (domain == null)
- {
- function2Value[func.Name] = defaultElem.Bottom();
- }
- else
- {
- function2Value[func.Name] = AbstractDomainFactory.GetInstance(domain);
- }
- }
- existentialFunctions.Keys.Iter(f => function2implAssumed.Add(f, new HashSet<string>()));
- existentialFunctions.Keys.Iter(f => function2implAsserted.Add(f, new HashSet<string>()));
-
- // type check
- existentialFunctions.Values.Iter(func =>
- {
- if (func.OutParams.Count != 1 || !func.OutParams[0].TypedIdent.Type.IsBool)
- throw new AbsHoudiniInternalError(string.Format("Existential function {0} must return bool", func.Name));
- if(func.Body != null)
- throw new AbsHoudiniInternalError(string.Format("Existential function {0} should not have a body", func.Name));
- var args = new List<Type>();
- func.InParams.Iter(v => args.Add(v.TypedIdent.Type));
- string msg = "";
- if (!function2Value[func.Name].TypeCheck(args, out msg))
- throw new AbsHoudiniInternalError("TypeError: " + msg);
- });
-
- //if (CommandLineOptions.Clo.ProverKillTime > 0)
- // CommandLineOptions.Clo.ProverOptions.Add(string.Format("TIME_LIMIT={0}", CommandLineOptions.Clo.ProverKillTime));
-
- Inline();
-
- this.vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List<Checker>());
- this.prover = ProverInterface.CreateProver(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, CommandLineOptions.Clo.ProverKillTime);
-
- this.proverTime = TimeSpan.Zero;
- this.numProverQueries = 0;
-
- program.Implementations
- .Where(impl => !impl.SkipVerification)
- .Iter(impl => name2Impl.Add(impl.Name, impl));
-
- // Let's do VC Gen (and also build dependencies)
- name2Impl.Values.Iter(GenVC);
- }
-
- public VCGenOutcome ComputeSummaries()
- {
- var overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Valid, new List<Counterexample>());
-
- // Compute SCCs and determine a priority order for impls
- var Succ = new Dictionary<string, HashSet<string>>();
- var Pred = new Dictionary<string, HashSet<string>>();
- name2Impl.Keys.Iter(s => Succ[s] = new HashSet<string>());
- name2Impl.Keys.Iter(s => Pred[s] = new HashSet<string>());
-
- foreach(var impl in name2Impl.Keys) {
- Succ[impl] = new HashSet<string>();
- impl2functionsAsserted[impl].Iter(f =>
- function2implAssumed[f].Iter(succ =>
- {
- Succ[impl].Add(succ);
- Pred[succ].Add(impl);
- }));
- }
-
- var sccs = new StronglyConnectedComponents<string>(name2Impl.Keys,
- new Adjacency<string>(n => Pred[n]),
- new Adjacency<string>(n => Succ[n]));
- sccs.Compute();
-
- // impl -> priority
- var impl2Priority = new Dictionary<string, int>();
- int p = 0;
- foreach (var scc in sccs)
- {
- foreach (var impl in scc)
- {
- impl2Priority.Add(impl, p);
- p++;
- }
- }
-
- var worklist = new SortedSet<Tuple<int, string>>();
- name2Impl.Keys.Iter(k => worklist.Add(Tuple.Create(impl2Priority[k], k)));
-
- while (worklist.Any())
- {
- var impl = worklist.First().Item2;
- worklist.Remove(worklist.First());
-
- var gen = prover.VCExprGen;
- var terms = new List<Expr>();
- foreach (var tup in impl2FuncCalls[impl])
- {
- var controlVar = tup.Item2;
- var exprVars = tup.Item3;
- var varList = new List<Expr>();
- exprVars.Args.OfType<Expr>().Iter(v => varList.Add(v));
-
- var args = new List<Expr>();
- controlVar.InParams.Iter(v => args.Add(Expr.Ident(v)));
- Expr term = Expr.Eq(new NAryExpr(Token.NoToken, new FunctionCall(controlVar), args),
- function2Value[tup.Item1].Gamma(varList));
-
- if (controlVar.InParams.Count != 0)
- {
- term = new ForallExpr(Token.NoToken, new List<Variable>(controlVar.InParams.ToArray()),
- new Trigger(Token.NoToken, true, new List<Expr> { new NAryExpr(Token.NoToken, new FunctionCall(controlVar), args) }),
- term);
- }
- terms.Add(term);
- }
- var env = Expr.BinaryTreeAnd(terms);
-
- env.Typecheck(new TypecheckingContext((IErrorSink)null));
- var envVC = prover.Context.BoogieExprTranslator.Translate(env);
-
- var vc = gen.Implies(envVC, impl2VC[impl]);
-
- if (CommandLineOptions.Clo.Trace)
- {
- Console.WriteLine("Verifying {0}: ", impl);
- //Console.WriteLine("env: {0}", envVC);
- var envFuncs = new HashSet<string>();
- impl2FuncCalls[impl].Iter(tup => envFuncs.Add(tup.Item1));
- envFuncs.Iter(f => PrintFunction(existentialFunctions[f]));
- }
-
- var handler = impl2ErrorHandler[impl].Item1;
- var collector = impl2ErrorHandler[impl].Item2;
- collector.Reset(impl);
-
- var start = DateTime.Now;
-
- prover.Push();
- prover.Assert(gen.Not(vc), true);
- prover.FlushAxiomsToTheoremProver();
- prover.Check();
- ProverInterface.Outcome proverOutcome = prover.CheckOutcomeCore(handler);
-
- //prover.BeginCheck(impl, vc, handler);
- //ProverInterface.Outcome proverOutcome = prover.CheckOutcomeCore(handler);
-
- var inc = (DateTime.Now - start);
- proverTime += inc;
- numProverQueries++;
-
- if (CommandLineOptions.Clo.Trace)
- Console.WriteLine("Time taken = " + inc.TotalSeconds.ToString());
-
- if (proverOutcome == ProverInterface.Outcome.TimeOut || proverOutcome == ProverInterface.Outcome.OutOfMemory)
- {
- // pick some function; make it true and keep going
- bool changed = false;
- foreach (var f in impl2functionsAsserted[impl])
- {
- function2Value[f] = function2Value[f].MakeTop(out changed);
- if (changed) break;
- }
- if(!changed)
- return new VCGenOutcome(proverOutcome, new List<Counterexample>());
- }
-
- if (CommandLineOptions.Clo.Trace)
- Console.WriteLine(collector.numErrors > 0 ? "SAT" : "UNSAT");
-
- if (collector.numErrors > 0)
- {
- var funcsChanged = collector.funcsChanged;
- if (funcsChanged.Count == 0)
- {
- overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.errors);
- break;
- }
-
- // propagate dependent guys back into the worklist, including self
- var deps = new HashSet<string>();
- deps.Add(impl);
- funcsChanged.Iter(f => deps.UnionWith(function2implAssumed[f]));
-
- deps.Iter(s => worklist.Add(Tuple.Create(impl2Priority[s], s)));
- }
-
- prover.Pop();
- }
-
- if (CommandLineOptions.Clo.Trace)
- {
- Console.WriteLine("Prover time = {0}", proverTime.TotalSeconds.ToString("F2"));
- Console.WriteLine("Number of prover queries = " + numProverQueries);
- }
-
- if (CommandLineOptions.Clo.PrintAssignment)
- {
- // Print the answer
- existentialFunctions.Values.Iter(PrintFunction);
- }
-
- return overallOutcome;
- }
-
-
- public IEnumerable<Function> GetAssignment()
- {
- var ret = new List<Function>();
- foreach (var func in existentialFunctions.Values)
- {
- var invars = new List<Expr>(func.InParams.OfType<Variable>().Select(v => Expr.Ident(v)));
- func.Body = function2Value[func.Name].Gamma(invars);
- ret.Add(func);
- }
- return ret;
- }
-
- private void PrintFunction(Function function)
- {
- var tt = new TokenTextWriter(Console.Out, /*pretty=*/ false);
- var invars = new List<Expr>(function.InParams.OfType<Variable>().Select(v => Expr.Ident(v)));
- function.Body = function2Value[function.Name].Gamma(invars);
- function.Emit(tt, 0);
- tt.Close();
- }
-
- public HashSet<string> HandleCounterExample(string impl, Counterexample error)
- {
- var funcsChanged = new HashSet<string>();
- // Find the failing assert -- need to do a join there
- // return the set of functions whose definition has changed
- var cex = ExtractState(impl, error);
- foreach (var tup in cex)
- {
- function2Value[tup.Item1] = function2Value[tup.Item1].Join(tup.Item2);
- funcsChanged.Add(tup.Item1);
- }
- return funcsChanged;
- }
-
- private List<Tuple<string, List<Model.Element>>> ExtractState(string impl, Counterexample error)
- {
- var lastBlock = error.Trace.Last() as Block;
- AssertCmd failingAssert = null;
-
- CallCounterexample callCounterexample = error as CallCounterexample;
- if (callCounterexample != null)
- {
- Procedure failingProcedure = callCounterexample.FailingCall.Proc;
- Requires failingRequires = callCounterexample.FailingRequires;
- failingAssert = lastBlock.Cmds.OfType<AssertRequiresCmd>().FirstOrDefault(ac => ac.Requires == failingRequires);
- }
- ReturnCounterexample returnCounterexample = error as ReturnCounterexample;
- if (returnCounterexample != null)
- {
- Ensures failingEnsures = returnCounterexample.FailingEnsures;
- failingAssert = lastBlock.Cmds.OfType<AssertEnsuresCmd>().FirstOrDefault(ac => ac.Ensures == failingEnsures);
- }
- AssertCounterexample assertCounterexample = error as AssertCounterexample;
- if (assertCounterexample != null)
- {
- failingAssert = lastBlock.Cmds.OfType<AssertCmd>().FirstOrDefault(ac => ac == assertCounterexample.FailingAssert);
- }
-
- Debug.Assert(failingAssert != null);
- return ExtractState(impl, failingAssert.Expr, error.Model);
- }
-
- private static int existentialConstCounter = 0;
-
- private List<Tuple<string, List<Model.Element>>> ExtractState(string impl, Expr expr, Model model)
- {
- var funcsUsed = FunctionCollector.Collect(expr);
-
- var ret = new List<Tuple<string, List<Model.Element>>>();
-
- foreach (var tup in funcsUsed.Where(t => t.Item2 == null))
- {
- var constant = tup.Item1;
- if (!constant2FuncCall.ContainsKey(constant.Name))
- continue;
-
- var func = constant2FuncCall[constant.Name];
- var funcName = (func.Fun as FunctionCall).FunctionName;
- var vals = new List<Model.Element>();
- prover.Context.BoogieExprTranslator.Translate(func.Args).Iter(ve => vals.Add(getValue(ve, model)));
- ret.Add(Tuple.Create(funcName, vals));
- }
-
- foreach (var tup in funcsUsed.Where(t => t.Item2 != null))
- {
- var constant = tup.Item1;
- var boundExpr = tup.Item2;
-
- if (!constant2FuncCall.ContainsKey(constant.Name))
- continue;
-
- // There are some bound variables (because the existential function was inside an \exists).
- // We must find an assignment for bound varibles
-
- // First, peice apart the existential functions
- var cd = new Duplicator();
- var tup2 = ExistentialExprModelMassage.Massage(cd.VisitExpr(boundExpr.Body));
- var be = tup2.Item1;
- Expr env = Expr.True;
- foreach (var ahFunc in tup2.Item2)
- {
- var tup3 = impl2FuncCalls[impl].First(t => t.Item2.Name == ahFunc.Name);
- var varList = new List<Expr>();
- tup3.Item3.Args.OfType<Expr>().Iter(v => varList.Add(v));
-
- env = Expr.And(env, function2Value[tup3.Item1].Gamma(varList));
- }
- be = Expr.And(be, Expr.Not(env));
-
- // map formals to constants
- var formalToConstant = new Dictionary<string, Constant>();
- foreach (var f in boundExpr.Dummies.OfType<Variable>())
- formalToConstant.Add(f.Name, new Constant(Token.NoToken, new TypedIdent(Token.NoToken, f.Name + "@subst@" + (existentialConstCounter++), f.TypedIdent.Type), false));
- be = Substituter.Apply(new Substitution(v => formalToConstant.ContainsKey(v.Name) ? Expr.Ident(formalToConstant[v.Name]) : Expr.Ident(v)), be);
- formalToConstant.Values.Iter(v => prover.Context.DeclareConstant(v, false, null));
-
- var reporter = new AbstractHoudiniErrorReporter();
- var ve = prover.Context.BoogieExprTranslator.Translate(be);
- prover.Assert(ve, true);
- prover.Check();
- var proverOutcome = prover.CheckOutcomeCore(reporter);
- if (proverOutcome != ProverInterface.Outcome.Invalid)
- continue;
- model = reporter.model;
-
- var func = constant2FuncCall[constant.Name];
- var funcName = (func.Fun as FunctionCall).FunctionName;
- var vals = new List<Model.Element>();
- foreach (var funcArg in func.Args.OfType<Expr>())
- {
- var arg = Substituter.Apply(new Substitution(v => formalToConstant.ContainsKey(v.Name) ? Expr.Ident(formalToConstant[v.Name]) : Expr.Ident(v)), funcArg);
- vals.Add(getValue(prover.Context.BoogieExprTranslator.Translate(arg), model));
- }
- ret.Add(Tuple.Create(funcName, vals));
-
- }
-
- return ret;
- }
-
- private Model.Element getValue(VCExpr arg, Model model)
- {
-
-
- if (arg is VCExprLiteral)
- {
- //return model.GetElement(arg.ToString());
- return model.MkElement(arg.ToString());
- }
-
- else if (arg is VCExprVar)
- {
- var el = model.TryGetFunc(prover.Context.Lookup(arg as VCExprVar));
- if (el != null)
- {
- Debug.Assert(el.Arity == 0 && el.AppCount == 1);
- return el.Apps.First().Result;
- }
- else
- {
- // Variable not defined; assign arbitrary value
- if (arg.Type.IsBool)
- return model.MkElement("false");
- else if (arg.Type.IsInt)
- return model.MkIntElement(0);
- else
- return null;
- }
- }
- else if (arg is VCExprNAry && (arg as VCExprNAry).Op is VCExprBvOp)
- {
- // support for BV constants
- var bvc = (arg as VCExprNAry)[0] as VCExprLiteral;
- if (bvc != null)
- {
- var ret = model.TryMkElement(bvc.ToString() + arg.Type.ToString());
- if (ret != null && (ret is Model.BitVector)) return ret;
- }
- }
-
- var val = prover.Evaluate(arg);
- if (val is int || val is bool || val is Microsoft.Basetypes.BigNum)
- {
- return model.MkElement(val.ToString());
- }
- else
- {
- Debug.Assert(false);
- }
- return null;
- }
-
- // Remove functions AbsHoudiniConstant from the expressions and substitute them with "true"
- class ExistentialExprModelMassage : StandardVisitor
- {
- List<Function> ahFuncs;
-
- public ExistentialExprModelMassage()
- {
- ahFuncs = new List<Function>();
- }
-
- public static Tuple<Expr, List<Function>> Massage(Expr expr)
- {
- var ee = new ExistentialExprModelMassage();
- expr = ee.VisitExpr(expr);
- return Tuple.Create(expr, ee.ahFuncs);
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- if (node.Fun is FunctionCall && (node.Fun as FunctionCall).FunctionName.StartsWith("AbsHoudiniConstant"))
- {
- ahFuncs.Add((node.Fun as FunctionCall).Func);
- return Expr.True;
- }
-
- return base.VisitNAryExpr(node);
- }
- }
-
- class FunctionCollector : ReadOnlyVisitor
- {
- public List<Tuple<Function, ExistsExpr>> functionsUsed;
- ExistsExpr existentialExpr;
-
- public FunctionCollector()
- {
- functionsUsed = new List<Tuple<Function, ExistsExpr>>();
- existentialExpr = null;
- }
-
- public static List<Tuple<Function, ExistsExpr>> Collect(Expr expr)
- {
- var fv = new FunctionCollector();
- fv.VisitExpr(expr);
- return fv.functionsUsed;
- }
-
- public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
- {
- var oldE = existentialExpr;
-
- if (node is ExistsExpr)
- existentialExpr = (node as ExistsExpr);
-
- node = base.VisitQuantifierExpr(node);
-
- existentialExpr = oldE;
- return node;
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- if (node.Fun is FunctionCall)
- {
- var collector = new VariableCollector();
- collector.Visit(node);
-
- if(existentialExpr != null && existentialExpr.Dummies.Intersect(collector.usedVars).Any())
- functionsUsed.Add(Tuple.Create((node.Fun as FunctionCall).Func, existentialExpr));
- else
- functionsUsed.Add(Tuple.Create<Function, ExistsExpr>((node.Fun as FunctionCall).Func, null));
- }
-
- return base.VisitNAryExpr(node);
- }
- }
-
- class AbsHoudiniCounterexampleCollector : VerifierCallback
- {
- public HashSet<string> funcsChanged;
- public string currImpl;
- public int numErrors;
- public List<Counterexample> errors;
-
- AbsHoudini container;
-
- public AbsHoudiniCounterexampleCollector(AbsHoudini container)
- {
- this.container = container;
- Reset(null);
- }
-
- public void Reset(string impl)
- {
- funcsChanged = new HashSet<string>();
- currImpl = impl;
- numErrors = 0;
- errors = new List<Counterexample>();
- }
-
- public override void OnCounterexample(Counterexample ce, string reason)
- {
- numErrors++;
- errors.Add(ce);
-
- funcsChanged.UnionWith(
- container.HandleCounterExample(currImpl, ce));
- }
- }
-
- private void GenVC(Implementation impl)
- {
- ModelViewInfo mvInfo;
- Dictionary<int, Absy> label2absy;
- var collector = new AbsHoudiniCounterexampleCollector(this);
- collector.OnProgress("HdnVCGen", 0, 0, 0.0);
-
- if (CommandLineOptions.Clo.Trace)
- {
- Console.WriteLine("Generating VC of {0}", impl.Name);
- }
-
- vcgen.ConvertCFG2DAG(impl);
- var gotoCmdOrigins = vcgen.PassifyImpl(impl, out mvInfo);
-
- // Inline functions
- (new InlineFunctionCalls()).VisitBlockList(impl.Blocks);
-
- ExtractQuantifiedExprs(impl);
- StripOutermostForall(impl);
-
- //CommandLineOptions.Clo.PrintInstrumented = true;
- //var tt = new TokenTextWriter(Console.Out);
- //impl.Emit(tt, 0);
- //tt.Close();
-
- // Intercept the FunctionCalls of the existential functions, and replace them with Boolean constants
- var existentialFunctionNames = new HashSet<string>(existentialFunctions.Keys);
- var fv = new ReplaceFunctionCalls(existentialFunctionNames);
- fv.VisitBlockList(impl.Blocks);
-
- impl2functionsAsserted.Add(impl.Name, fv.functionsAsserted);
- impl2functionsAssumed.Add(impl.Name, fv.functionsAssumed);
-
- fv.functionsAssumed.Iter(f => function2implAssumed[f].Add(impl.Name));
- fv.functionsAsserted.Iter(f => function2implAsserted[f].Add(impl.Name));
-
- impl2FuncCalls.Add(impl.Name, fv.functionsUsed);
- fv.functionsUsed.Iter(tup => constant2FuncCall.Add(tup.Item2.Name, tup.Item3));
-
- var gen = prover.VCExprGen;
- VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : gen.Integer(Microsoft.Basetypes.BigNum.ZERO);
-
- var vcexpr = vcgen.GenerateVC(impl, controlFlowVariableExpr, out label2absy, prover.Context);
- if (!CommandLineOptions.Clo.UseLabels)
- {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(gen.Integer(Microsoft.Basetypes.BigNum.ZERO), gen.Integer(Microsoft.Basetypes.BigNum.ZERO));
- VCExpr eqExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(Microsoft.Basetypes.BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vcexpr = gen.Implies(eqExpr, vcexpr);
- }
-
- ProverInterface.ErrorHandler handler = null;
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local)
- handler = new VCGen.ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, vcgen.incarnationOriginMap, collector, mvInfo, prover.Context, program);
- else
- handler = new VCGen.ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, vcgen.incarnationOriginMap, collector, mvInfo, prover.Context, program);
-
- impl2ErrorHandler.Add(impl.Name, Tuple.Create(handler, collector));
-
- //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr);
-
- // Create a macro so that the VC can sit with the theorem prover
- Macro macro = new Macro(Token.NoToken, impl.Name + "Macro", new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false));
- prover.DefineMacro(macro, vcexpr);
-
- // Store VC
- impl2VC.Add(impl.Name, gen.Function(macro));
-
- // HACK: push the definitions of constants involved in function calls
- // It is possible that some constants only appear in function calls. Thus, when
- // they are replaced by Boolean constants, it is possible that (get-value) will
- // fail if the expression involves such constants. All we need to do is make sure
- // these constants are declared, because otherwise, semantically we are doing
- // the right thing.
- foreach (var tup in fv.functionsUsed)
- {
- // Ignore ones with bound varibles
- if (tup.Item2.InParams.Count > 0) continue;
- var tt = prover.Context.BoogieExprTranslator.Translate(tup.Item3);
- tt = prover.VCExprGen.Or(VCExpressionGenerator.True, tt);
- prover.Assert(tt, true);
- }
- }
-
- // convert "foo(... forall e ...) to:
- // (p iff forall e) ==> foo(... p ...)
- // where p is a fresh boolean variable and foo is an existential constant
- private void ExtractQuantifiedExprs(Implementation impl)
- {
- var funcs = new HashSet<string>(existentialFunctions.Keys);
- foreach (var blk in impl.Blocks)
- {
- foreach (var acmd in blk.Cmds.OfType<AssertCmd>())
- {
- var ret = ExtractQuantifiers.Extract(acmd.Expr, funcs);
- acmd.Expr = ret.Item1;
- impl.LocVars.AddRange(ret.Item2);
- }
- }
- }
-
- // convert "assert e1 && forall x: e2" to
- // assert e1 && e2[x <- x@bound]
- private void StripOutermostForall(Implementation impl)
- {
- var funcs = new HashSet<string>(existentialFunctions.Keys);
- foreach (var blk in impl.Blocks)
- {
- foreach (var acmd in blk.Cmds.OfType<AssertCmd>())
- {
- var ret = StripQuantifiers.Run(acmd.Expr, funcs);
- acmd.Expr = ret.Item1;
- impl.LocVars.AddRange(ret.Item2);
- }
- }
- }
-
- private void Inline()
- {
- if (CommandLineOptions.Clo.InlineDepth < 0)
- return;
-
- var callGraph = BuildCallGraph();
-
- foreach (Implementation impl in callGraph.Nodes)
- {
- InlineEnsuresVisitor inlineEnsuresVisitor = new InlineEnsuresVisitor();
- inlineEnsuresVisitor.Visit(impl);
- }
-
- foreach (Implementation impl in callGraph.Nodes)
- {
- impl.OriginalBlocks = impl.Blocks;
- impl.OriginalLocVars = impl.LocVars;
- }
- foreach (Implementation impl in callGraph.Nodes)
- {
- CommandLineOptions.Inlining savedOption = CommandLineOptions.Clo.ProcedureInlining;
- CommandLineOptions.Clo.ProcedureInlining = CommandLineOptions.Inlining.Spec;
- Inliner.ProcessImplementationForHoudini(program, impl);
- CommandLineOptions.Clo.ProcedureInlining = savedOption;
- }
- foreach (Implementation impl in callGraph.Nodes)
- {
- impl.OriginalBlocks = null;
- impl.OriginalLocVars = null;
- }
-
- Graph<Implementation> oldCallGraph = callGraph;
- callGraph = new Graph<Implementation>();
- foreach (Implementation impl in oldCallGraph.Nodes)
- {
- callGraph.AddSource(impl);
- }
- foreach (Tuple<Implementation, Implementation> edge in oldCallGraph.Edges)
- {
- callGraph.AddEdge(edge.Item1, edge.Item2);
- }
- int count = CommandLineOptions.Clo.InlineDepth;
- while (count > 0)
- {
- foreach (Implementation impl in oldCallGraph.Nodes)
- {
- List<Implementation> newNodes = new List<Implementation>();
- foreach (Implementation succ in callGraph.Successors(impl))
- {
- newNodes.AddRange(oldCallGraph.Successors(succ));
- }
- foreach (Implementation newNode in newNodes)
- {
- callGraph.AddEdge(impl, newNode);
- }
- }
- count--;
- }
- }
-
- private Graph<Implementation> BuildCallGraph()
- {
- Graph<Implementation> callGraph = new Graph<Implementation>();
- Dictionary<Procedure, HashSet<Implementation>> procToImpls = new Dictionary<Procedure, HashSet<Implementation>>();
- foreach (var proc in program.Procedures)
- {
- procToImpls[proc] = new HashSet<Implementation>();
- }
- foreach (var impl in program.Implementations)
- {
- if (impl.SkipVerification) continue;
- callGraph.AddSource(impl);
- procToImpls[impl.Proc].Add(impl);
- }
- foreach (var impl in program.Implementations)
- {
- if (impl.SkipVerification) continue;
- foreach (Block b in impl.Blocks)
- {
- foreach (Cmd c in b.Cmds)
- {
- CallCmd cc = c as CallCmd;
- if (cc == null) continue;
- foreach (Implementation callee in procToImpls[cc.Proc])
- {
- callGraph.AddEdge(impl, callee);
- }
- }
- }
- }
- return callGraph;
- }
-
- }
-
- class InlineFunctionCalls : StandardVisitor
- {
- public Stack<string> inlinedFunctionsStack;
-
- public InlineFunctionCalls()
- {
- inlinedFunctionsStack = new Stack<string>();
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- var fc = node.Fun as FunctionCall;
- if (fc != null && fc.Func.Body != null && QKeyValue.FindBoolAttribute(fc.Func.Attributes, "inline"))
- {
- if (inlinedFunctionsStack.Contains(fc.Func.Name))
- {
- // recursion detected
- throw new AbsHoudiniInternalError("Recursion detected in function declarations");
- }
-
- // create a substitution
- var subst = new Dictionary<Variable, Expr>();
- for (int i = 0; i < node.Args.Count; i++)
- {
- subst.Add(fc.Func.InParams[i], node.Args[i]);
- }
-
- var e =
- Substituter.Apply(new Substitution(v => subst.ContainsKey(v) ? subst[v] : Expr.Ident(v)), fc.Func.Body);
-
- inlinedFunctionsStack.Push(fc.Func.Name);
-
- e = base.VisitExpr(e);
-
- inlinedFunctionsStack.Pop();
-
- return e;
- }
- return base.VisitNAryExpr(node);
- }
- }
-
- class ReplaceFunctionCalls : StandardVisitor
- {
- public List<Tuple<string, Function, NAryExpr>> functionsUsed;
- public List<Function> boolConstants;
-
- public HashSet<string> functionsAssumed;
- public HashSet<string> functionsAsserted;
- HashSet<string> functionsToReplace;
-
- private bool inAssume;
- private bool inAssert;
- private bool inFunction;
- private List<Dictionary<string, Variable>> boundVars;
- private static int IdCounter = 0;
-
- public ReplaceFunctionCalls(HashSet<string> functionsToReplace)
- {
- this.functionsUsed = new List<Tuple<string, Function, NAryExpr>>();
- this.functionsToReplace = functionsToReplace;
- this.functionsAsserted = new HashSet<string>();
- this.functionsAssumed = new HashSet<string>();
- this.boolConstants = new List<Function>();
- this.boundVars = new List<Dictionary<string, Variable>>();
-
- inAssume = false;
- inAssert = false;
- inFunction = false;
- }
-
- public override Cmd VisitAssertCmd(AssertCmd node)
- {
- inAssert = true;
- var ret = base.VisitAssertCmd(node);
- inAssert = false;
- return ret;
- }
-
- public override Cmd VisitAssertEnsuresCmd(AssertEnsuresCmd node)
- {
- return this.VisitAssertCmd(node);
- }
-
- public override Cmd VisitAssertRequiresCmd(AssertRequiresCmd node)
- {
- return this.VisitAssertCmd(node);
- }
-
- public override Cmd VisitAssumeCmd(AssumeCmd node)
- {
- inAssume = true;
- var ret = base.VisitAssumeCmd(node);
- inAssume = false;
- return ret;
- }
-
- public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
- {
- // gather the quantified variables
- var dummies = new Dictionary<string, Variable>();
- node.Dummies.Iter(v => dummies.Add(v.Name, v));
-
- boundVars.Add(dummies);
-
- node = base.VisitQuantifierExpr(node);
-
- boundVars.RemoveAt(boundVars.Count - 1);
-
- return node;
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- var inF = inFunction;
-
- if (node.Fun is FunctionCall && functionsToReplace.Contains((node.Fun as FunctionCall).FunctionName))
- {
- found((node.Fun as FunctionCall).FunctionName);
- inFunction = true;
-
- // collect all the variables used by this function
- var collector = new VariableCollector();
- collector.VisitExpr(node);
-
- // Find the outermost bound variables
- var bound = new List<Variable>();
- if(boundVars.Count > 0)
- bound.AddRange(collector.usedVars.Intersect(boundVars[0].Values));
-
- // create boolean function to replace this guy
- var constant = new Function(Token.NoToken, "AbsHoudiniConstant" + IdCounter, bound,
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "r", Microsoft.Boogie.Type.Bool), false));
- IdCounter++;
-
- functionsUsed.Add(Tuple.Create((node.Fun as FunctionCall).FunctionName, constant, node));
- boolConstants.Add(constant);
-
- var args = new List<Expr>();
- bound.OfType<Variable>().Select(v => Expr.Ident(v)).Iter(v => args.Add(v));
- return new NAryExpr(Token.NoToken, new FunctionCall(constant), args);
- }
- var ret = base.VisitNAryExpr(node);
-
- inFunction = inF;
-
- return ret;
- }
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- if (inFunction)
- {
- // Inside functions we can only refer to the outermost bound variables
- for (int i = boundVars.Count - 1; i >= 1; i--)
- {
- if (boundVars[i].ContainsKey(node.Name))
- throw new AbsHoudiniInternalError("Existential functions can only refer to outermost bound variables in an expression");
- }
- }
-
- return base.VisitIdentifierExpr(node);
- }
-
- private void found(string func)
- {
- if (inAssume) functionsAssumed.Add(func);
- if (inAssert) functionsAsserted.Add(func);
- }
-
- }
-
- // convert "foo(... forall e ...) to:
- // (p iff forall e) ==> foo(... p ...)
- // where p is a fresh boolean variable and foo is an existential constant
- class ExtractQuantifiers : StandardVisitor
- {
- static int freshConstCounter = 0;
- HashSet<string> existentialFunctions;
- bool insideExistential;
- Dictionary<Constant, Expr> newConstants;
-
- private ExtractQuantifiers(HashSet<string> existentialFunctions)
- {
- this.existentialFunctions = existentialFunctions;
- insideExistential = false;
- newConstants = new Dictionary<Constant, Expr>();
- }
-
- public static Tuple<Expr, IEnumerable<Constant>> Extract(Expr expr, HashSet<string> existentialFunctions)
- {
- var eq = new ExtractQuantifiers(existentialFunctions);
- expr = eq.VisitExpr(expr);
- Expr ret = Expr.True;
- foreach (var tup in eq.newConstants)
- {
- ret = Expr.And(ret, Expr.Eq(Expr.Ident(tup.Key), tup.Value));
- }
- ret = Expr.Imp(ret, expr);
- return Tuple.Create(ret, eq.newConstants.Keys.AsEnumerable());
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- var oldIE = insideExistential;
-
- if (node.Fun is FunctionCall && existentialFunctions.Contains((node.Fun as FunctionCall).FunctionName))
- insideExistential = true;
-
- var ret = base.VisitNAryExpr(node);
-
- insideExistential = oldIE;
- return ret;
- }
-
- public override Expr VisitExpr(Expr node)
- {
- if (node is QuantifierExpr)
- {
- return MyVisitQuantifierExpr(node as QuantifierExpr);
- }
- return base.VisitExpr(node);
- }
-
- public Expr MyVisitQuantifierExpr(QuantifierExpr node)
- {
- node = base.VisitQuantifierExpr(node);
-
- if (insideExistential)
- {
- var constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
- "quant@const" + freshConstCounter, Microsoft.Boogie.Type.Bool), false);
- freshConstCounter++;
-
- newConstants.Add(constant, node);
-
- return Expr.Ident(constant);
- }
-
- return node;
- }
- }
-
- // convert "assert e1 && forall x: e2" to
- // assert e1 && e2[x <- x@bound]
- // only if e2 has an existential function
- class StripQuantifiers : StandardVisitor
- {
- static int boundVarCounter = 0;
-
- // 0 -> None, 1 -> Forall, 2 -> Exists, 3 -> Nested
- int insideQuantifier;
-
- bool searchExistentialFunction;
- bool foundExistentialFunction;
-
- HashSet<string> existentialFunctions;
- Dictionary<string, LocalVariable> subst;
- List<LocalVariable> LocalsToAdd;
-
- private StripQuantifiers(HashSet<string> existentialFunctions)
- {
- this.existentialFunctions = existentialFunctions;
- insideQuantifier = 0;
- searchExistentialFunction = false;
- foundExistentialFunction = false;
- LocalsToAdd = new List<LocalVariable>();
- subst = null;
- }
-
- public static Tuple<Expr,List<LocalVariable>> Run(Expr expr, HashSet<string> existentialFunctions)
- {
- // check for type errors first
- var sq = new StripQuantifiers(existentialFunctions);
- var ret = sq.VisitExpr(expr);
-
- return Tuple.Create(ret, sq.LocalsToAdd);
- }
-
- public override Expr VisitExpr(Expr node)
- {
- if (node is QuantifierExpr)
- {
- return MyVisitQuantifierExpr(node as QuantifierExpr);
- }
-
- return base.VisitExpr(node);
- }
-
- private Expr MyVisitQuantifierExpr(QuantifierExpr node)
- {
- var oldIQ = insideQuantifier;
- Expr ret = node;
-
- // update "insideQuantifier"
- if (insideQuantifier == 0)
- {
- if (node is ForallExpr) insideQuantifier = 1;
- else insideQuantifier = 2;
- }
- else if (insideQuantifier > 0)
- {
- insideQuantifier = 3;
- }
-
- // Going inside Forall?
- if (insideQuantifier == 1)
- {
- // see if there is any existential function inside
- searchExistentialFunction = true;
- foundExistentialFunction = false;
- base.VisitQuantifierExpr(node);
-
- if (foundExistentialFunction)
- {
- // create substitution to apply
- subst = new Dictionary<string, LocalVariable>();
- foreach (var bv in node.Dummies.OfType<Variable>())
- {
- var lv = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken,
- bv + "@bound" + boundVarCounter, bv.TypedIdent.Type));
- boundVarCounter++;
- subst.Add(bv.Name, lv);
- LocalsToAdd.Add(lv);
- }
-
- // apply the subst
- var body = base.VisitExpr(node.Body);
- ret = body;
-
- subst = null;
- }
- else
- {
- ret = base.VisitQuantifierExpr(node);
- }
-
- searchExistentialFunction = false;
- foundExistentialFunction = false;
- }
- else
- {
- ret = base.VisitQuantifierExpr(node);
- }
-
- insideQuantifier = oldIQ;
- return ret;
- }
-
- public override Expr VisitNAryExpr(NAryExpr node)
- {
- if (node.Fun is FunctionCall && existentialFunctions.Contains((node.Fun as FunctionCall).FunctionName))
- {
- if (insideQuantifier == 3)
- throw new AbsHoudiniInternalError("Existential function found inside exists, or nested foralls");
-
- if (searchExistentialFunction)
- foundExistentialFunction = true;
-
- }
-
- return base.VisitNAryExpr(node);
- }
-
- public override Expr VisitIdentifierExpr(IdentifierExpr node)
- {
- if (subst != null && subst.ContainsKey(node.Name))
- return Expr.Ident(subst[node.Name]);
- return base.VisitIdentifierExpr(node);
- }
-
- }
-
- public class Intervals : IAbstractDomain
- {
- // [lower, upper]
- int upper;
- int lower;
- // or: \bot
- bool isBottom;
- // number of times join has been performed
- int nJoin;
- // number of times before we widen
- readonly static int maxJoin = 5;
-
- public Intervals()
- {
- this.upper = 0;
- this.lower = 0;
- this.nJoin = 0;
- this.isBottom = true;
- }
-
- private Intervals(int lower, int upper, int nJoin)
- {
- this.upper = upper;
- this.lower = lower;
- this.nJoin = nJoin;
- }
-
- public IAbstractDomain Bottom()
- {
- return new Intervals();
- }
-
- public IAbstractDomain MakeTop(out bool changed)
- {
- if (lower == Int32.MinValue && upper == Int32.MaxValue)
- {
- changed = false;
- return this;
- }
- changed = true;
- return new Intervals(Int32.MinValue, Int32.MaxValue, 0);
- }
-
- public IAbstractDomain Join(List<Model.Element> states)
- {
- Debug.Assert(states.Count == 1);
- var state = states[0] as Model.Integer;
- if (state == null)
- throw new AbsHoudiniInternalError("Incorrect type, expected int");
- var intval = state.AsInt();
-
- if (isBottom)
- {
- return new Intervals(intval, intval, 1);
- }
-
- if(intval >= lower && intval <= upper)
- return this;
-
- if (nJoin > maxJoin)
- {
- // widen
- if (intval > upper)
- return new Intervals(lower, Int32.MaxValue, 1);
- if(intval < lower)
- return new Intervals(Int32.MinValue, upper, 1);
-
- Debug.Assert(false);
- }
-
- if (intval > upper)
- return new Intervals(lower, intval, nJoin + 1);
- if (intval < lower)
- return new Intervals(intval, upper, nJoin + 1);
-
- Debug.Assert(false);
- return null;
- }
-
- public Expr Gamma(List<Expr> vars)
- {
- Debug.Assert(vars.Count == 1);
- var v = vars[0];
- if (isBottom) return Expr.False;
- Expr ret = Expr.True;
- if (lower != Int32.MinValue)
- ret = Expr.And(ret, Expr.Ge(v, Expr.Literal(lower)));
- if (upper != Int32.MaxValue)
- ret = Expr.And(ret, Expr.Le(v, Expr.Literal(upper)));
- return ret;
- }
-
- public bool TypeCheck(List<Type> argTypes, out string msg)
- {
- msg = "";
- if (argTypes.Count != 1)
- {
- msg = "Illegal number of arguments";
- return false;
- }
- if (!argTypes[0].IsInt)
- {
- msg = "Illegal type, expecting int";
- …
Large files files are truncated, but you can click here to view the full file