private VCGenOutcome LearnInv(Dictionary<string, int> impl2Priority) { 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()); #region vcgen 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); /* foreach (var variable in varList) { terms.Add(Expr.Le(variable, Expr.Literal(10))); terms.Add(Expr.Ge(variable, Expr.Literal(-10))); } */ } var env = BinaryTreeAnd(terms, 0, terms.Count - 1); 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])); } #endregion vcgen VCExpr finalVC; for (int i = 0; i <= bounds4cex.Count(); i++) { #region boundcexvalues /* Last iteration is when there are enforced no bounds on the cex values. */ if (i < bounds4cex.Count()) { int bound = bounds4cex.ElementAt(i); terms.Clear(); foreach (var tup in impl2FuncCalls[impl]) { var exprVars = tup.Item3; var varList = new List<Expr>(); exprVars.Args.OfType<Expr>().Where(v => v.Type.IsInt).Iter(v => varList.Add(v)); foreach (var variable in varList) { terms.Add(Expr.Le(variable, Expr.Literal(bound))); terms.Add(Expr.Ge(variable, Expr.Literal(-1 * bound))); //terms.Add(Expr.Ge(variable, Expr.Literal(0))); } } var boundcex = BinaryTreeAnd(terms, 0, terms.Count - 1); boundcex.Typecheck(new TypecheckingContext((IErrorSink)null)); var boundcexVC = prover.Context.BoogieExprTranslator.Translate(boundcex); finalVC = gen.Implies(boundcexVC, vc); } else { //finalVC = vc; int bound = 1000000; terms.Clear(); foreach (var tup in impl2FuncCalls[impl]) { var exprVars = tup.Item3; var varList = new List<Expr>(); exprVars.Args.OfType<Expr>().Where(v => v.Type.IsInt).Iter(v => varList.Add(v)); foreach (var variable in varList) { terms.Add(Expr.Le(variable, Expr.Literal(bound))); terms.Add(Expr.Ge(variable, Expr.Literal(-1 * bound))); //terms.Add(Expr.Ge(variable, Expr.Literal(0))); } } var boundcex = BinaryTreeAnd(terms, 0, terms.Count - 1); boundcex.Typecheck(new TypecheckingContext((IErrorSink)null)); var boundcexVC = prover.Context.BoogieExprTranslator.Translate(boundcex); finalVC = gen.Implies(boundcexVC, vc); } #endregion boundcexvalues var handler = impl2ErrorHandler[impl].Item1; var collector = impl2ErrorHandler[impl].Item2; collector.Reset(impl); implicationCounterExamples.Clear(); VCisValid = true; // set to false if control reaches HandleCounterExample //realErrorEncountered = false; //newSamplesAdded = false; //this.posNegCexAdded = false; var start = DateTime.Now; prover.Push(); prover.Assert(gen.Not(finalVC), true); prover.FlushAxiomsToTheoremProver(); prover.Check(); ProverInterface.Outcome proverOutcome = prover.CheckOutcomeCore(handler); var inc = (DateTime.Now - start); proverTime += inc; numProverQueries++; if (CommandLineOptions.Clo.Trace) Console.WriteLine("Prover Time taken = " + inc.TotalSeconds.ToString()); if (proverOutcome == ProverInterface.Outcome.TimeOut || proverOutcome == ProverInterface.Outcome.OutOfMemory) { Console.WriteLine("Z3 Prover for implementation {0} times out or runs out of memory !", impl); return new VCGenOutcome(proverOutcome, new List<Counterexample>()); } if (!VCisValid) { /* There was a counterexample found and acted upon while proving the method. */ if (collector.real_errors.Count > 0) { return new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.real_errors); } if (collector.conjecture_errors.Count == 0) { // No positive or negative counter-example added. Need to add implication counter-examples Debug.Assert(collector.implication_errors.Count > 0); foreach (var cex in implicationCounterExamples) { AddCounterExample(cex); } } //Debug.Assert(newSamplesAdded); HashSet<string> funcsChanged; if (!learn(out funcsChanged)) { // learner timed out, ran into some errors, or if there is no consistent conjecture prover.Pop(); if(collector.conjecture_errors.Count > 0) return new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.conjecture_errors); else return new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.implication_errors); } // propagate dependent guys back into the worklist, including self var deps = new HashSet<string>(); deps.Add(impl); funcsChanged.Iter(f => deps.UnionWith(function2implAssumed[f])); funcsChanged.Iter(f => deps.UnionWith(function2implAsserted[f])); deps.Iter(s => worklist.Add(Tuple.Create(impl2Priority[s], s))); // break out of the loop that iterates over various bounds. prover.Pop(); break; } else { prover.Pop(); } } } // The program was verified return new VCGenOutcome(ProverInterface.Outcome.Valid, new List<Counterexample>()); }
private ICEOutcome LearnInvFromTemplate(Dictionary<string, int> impl2Priority, Template t, int range, out VCGenOutcome overallOutcome) { overallOutcome = null; // create a new z3 context if (z3Context != null) { z3Context.context.Dispose(); z3Context.config.Dispose(); } z3Context = new Z3Context(); foreach (var func in existentialFunctions.Values) { // initialize function to an "Octagons" instance with the given template "t". function2Value[func.Name] = ICEDomainFactory.GetInstance("Octagons", t, ref z3Context, func.Name, range); } // add counterexamples into the z3Context. These are obtained from the earlier iterations of the template. foreach (var cex in counterExamples) { AddCounterExampleToZ3Context(cex); } 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()); #region vcgen 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 = BinaryTreeAnd(terms, 0, terms.Count - 1); 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])); } #endregion vcgen VCExpr finalVC; #region bound_value_of_cexs #if false finalVC = vc; #else int bound = 1000000; terms.Clear(); foreach (var tup in impl2FuncCalls[impl]) { var exprVars = tup.Item3; var varList = new List<Expr>(); exprVars.Args.OfType<Expr>().Where(v => v.Type.IsInt).Iter(v => varList.Add(v)); foreach (var variable in varList) { terms.Add(Expr.Le(variable, Expr.Literal(bound))); terms.Add(Expr.Ge(variable, Expr.Literal(-1 * bound))); //terms.Add(Expr.Ge(variable, Expr.Literal(0))); } } var boundcex = BinaryTreeAnd(terms, 0, terms.Count - 1); boundcex.Typecheck(new TypecheckingContext((IErrorSink)null)); var boundcexVC = prover.Context.BoogieExprTranslator.Translate(boundcex); finalVC = gen.Implies(boundcexVC, vc); #endif #endregion bound_value_of_cexs var handler = impl2ErrorHandler[impl].Item1; var collector = impl2ErrorHandler[impl].Item2; collector.Reset(impl); VCisValid = true; // set to false if control reaches HandleCounterExample realErrorEncountered = false; newSamplesAdded = false; var start = DateTime.Now; prover.Push(); prover.Assert(gen.Not(finalVC), 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("Prover Time taken = " + inc.TotalSeconds.ToString()); if (proverOutcome == ProverInterface.Outcome.TimeOut || proverOutcome == ProverInterface.Outcome.OutOfMemory) { Console.WriteLine("Z3 Prover for implementation {0} times out or runs out of memory !", impl); z3Context.context.Dispose(); z3Context.config.Dispose(); overallOutcome = new VCGenOutcome(proverOutcome, new List<Counterexample>()); return ICEOutcome.Timeout; } if (CommandLineOptions.Clo.Trace) Console.WriteLine(!VCisValid ? "SAT" : "UNSAT"); if (!VCisValid) { if (realErrorEncountered) { overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.real_errors); return ICEOutcome.ErrorFound; } Debug.Assert(newSamplesAdded); HashSet<string> funcsChanged; if (!learn(out funcsChanged)) { // learner timed out or there is no valid conjecture in the current given template overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Invalid, collector.conjecture_errors); prover.Pop(); return ICEOutcome.InvariantNotFound; } // propagate dependent guys back into the worklist, including self var deps = new HashSet<string>(); deps.Add(impl); funcsChanged.Iter(f => deps.UnionWith(function2implAssumed[f])); funcsChanged.Iter(f => deps.UnionWith(function2implAsserted[f])); deps.Iter(s => worklist.Add(Tuple.Create(impl2Priority[s], s))); } prover.Pop(); } // The program was verified with the current template! overallOutcome = new VCGenOutcome(ProverInterface.Outcome.Valid, new List<Counterexample>()); return ICEOutcome.InvariantFound; }
// MAXSAT public void Explain(ProverInterface proverInterface, Dictionary<Variable, bool> assignment, Variable refutedConstant) { Contract.Assert(CommandLineOptions.Clo.ExplainHoudini); collector.examples.Clear(); // debugging houdiniAssertConstants.Iter(v => System.Diagnostics.Debug.Assert(assignment.ContainsKey(v))); houdiniAssumeConstants.Iter(v => System.Diagnostics.Debug.Assert(assignment.ContainsKey(v))); Contract.Assert(assignment.ContainsKey(refutedConstant)); Contract.Assert(houdiniAssertConstants.Contains(refutedConstant)); var hardAssumptions = new List<VCExpr>(); var softAssumptions = new List<VCExpr>(); Boogie2VCExprTranslator exprTranslator = proverInterface.Context.BoogieExprTranslator; VCExpressionGenerator exprGen = proverInterface.VCExprGen; var controlExpr = VCExpressionGenerator.True; foreach (var tup in assignment) { Variable constant = tup.Key; VCExprVar exprVar = exprTranslator.LookupVariable(constant); var val = tup.Value; if (houdiniAssumeConstants.Contains(constant)) { if (tup.Value) hardAssumptions.Add(exprVar); else // Previously removed assumed candidates are the soft constraints softAssumptions.Add(exprVar); } else if (houdiniAssertConstants.Contains(constant)) { if (constant == refutedConstant) hardAssumptions.Add(exprVar); else hardAssumptions.Add(exprGen.Not(exprVar)); } else { if (tup.Value) hardAssumptions.Add(exprVar); else hardAssumptions.Add(exprGen.Not(exprVar)); } // For an asserted condition (c ==> \phi), // ExplainHoudini's extra control constants (c_pos, c_neg) are used as follows: // (true, true): "assert \phi" // (false, _): "assert false" // (true, false): "assert true" if (constant != refutedConstant && constantToControl.ContainsKey(constant.Name)) { var posControl = constantToControl[constant.Name].Item1; var negControl = constantToControl[constant.Name].Item2; // Handle self-recursion if (houdiniAssertConstants.Contains(constant) && houdiniAssumeConstants.Contains(constant)) { // disable this assert controlExpr = exprGen.And(controlExpr, exprGen.And(exprTranslator.LookupVariable(posControl), exprGen.Not(exprTranslator.LookupVariable(negControl)))); } else { // default values for control variables controlExpr = exprGen.And(controlExpr, exprGen.And(exprTranslator.LookupVariable(posControl), exprTranslator.LookupVariable(negControl))); } } } hardAssumptions.Add(exprGen.Not(conjecture)); // default values for control variables Contract.Assert(constantToControl.ContainsKey(refutedConstant.Name)); var pc = constantToControl[refutedConstant.Name].Item1; var nc = constantToControl[refutedConstant.Name].Item2; var controlExprNoop = exprGen.And(controlExpr, exprGen.And(exprTranslator.LookupVariable(pc), exprTranslator.LookupVariable(nc))); var controlExprFalse = exprGen.And(controlExpr, exprGen.And(exprGen.Not(exprTranslator.LookupVariable(pc)), exprGen.Not(exprTranslator.LookupVariable(nc)))); if (CommandLineOptions.Clo.Trace) { Console.WriteLine("Verifying (MaxSat) " + descriptiveName); } DateTime now = DateTime.UtcNow; var el = CommandLineOptions.Clo.ProverCCLimit; CommandLineOptions.Clo.ProverCCLimit = 1; var outcome = ProverInterface.Outcome.Undetermined; do { List<int> unsatisfiedSoftAssumptions; hardAssumptions.Add(controlExprNoop); outcome = proverInterface.CheckAssumptions(hardAssumptions, softAssumptions, out unsatisfiedSoftAssumptions, handler); hardAssumptions.RemoveAt(hardAssumptions.Count - 1); if (outcome == ProverInterface.Outcome.TimeOut || outcome == ProverInterface.Outcome.OutOfMemory || outcome == ProverInterface.Outcome.Undetermined) break; var reason = new HashSet<string>(); unsatisfiedSoftAssumptions.Iter(i => reason.Add(softAssumptions[i].ToString())); if (CommandLineOptions.Clo.Trace) { Console.Write("Reason for removal of {0}: ", refutedConstant.Name); reason.Iter(r => Console.Write("{0} ", r)); Console.WriteLine(); } // Get rid of those constants from the "reason" that can even make // "assert false" pass hardAssumptions.Add(controlExprFalse); var softAssumptions2 = new List<VCExpr>(); for (int i = 0; i < softAssumptions.Count; i++) { if (unsatisfiedSoftAssumptions.Contains(i)) { softAssumptions2.Add(softAssumptions[i]); continue; } hardAssumptions.Add(softAssumptions[i]); } var unsatisfiedSoftAssumptions2 = new List<int>(); outcome = proverInterface.CheckAssumptions(hardAssumptions, softAssumptions2, out unsatisfiedSoftAssumptions2, handler); if (outcome == ProverInterface.Outcome.TimeOut || outcome == ProverInterface.Outcome.OutOfMemory || outcome == ProverInterface.Outcome.Undetermined) break; unsatisfiedSoftAssumptions2.Iter(i => reason.Remove(softAssumptions2[i].ToString())); if (CommandLineOptions.Clo.Trace) { Console.Write("Revised reason for removal of {0}: ", refutedConstant.Name); reason.Iter(r => Console.Write("{0} ", r)); Console.WriteLine(); } foreach (var r in reason) { Houdini.explainHoudiniDottyFile.WriteLine("{0} -> {1} [ label = \"{2}\" color=red ];", refutedConstant.Name, r, descriptiveName); } } while (false); if (outcome == ProverInterface.Outcome.TimeOut || outcome == ProverInterface.Outcome.OutOfMemory || outcome == ProverInterface.Outcome.Undetermined) { Houdini.explainHoudiniDottyFile.WriteLine("{0} -> {1} [ label = \"{2}\" color=red ];", refutedConstant.Name, "TimeOut", descriptiveName); } CommandLineOptions.Clo.ProverCCLimit = el; double queryTime = (DateTime.UtcNow - now).TotalSeconds; stats.proverTime += queryTime; stats.numProverQueries++; if (CommandLineOptions.Clo.Trace) { Console.WriteLine("Time taken = " + queryTime); } }