From d4c0745b5d2bccbddc2d0c1fb3e0482742e7bb03 Mon Sep 17 00:00:00 2001
From: Etienne Kneuss <ekneuss@gmail.com>
Date: Thu, 15 Nov 2012 18:56:50 +0100
Subject: [PATCH] Propagate cores

---
 src/main/scala/leon/solvers/Solver.scala      |  1 -
 .../scala/leon/solvers/z3/FairZ3Solver.scala  | 87 +++++++------------
 src/main/scala/leon/testgen/CallGraph.scala   |  6 +-
 .../scala/leon/testgen/TestGeneration.scala   |  6 +-
 4 files changed, 36 insertions(+), 64 deletions(-)

diff --git a/src/main/scala/leon/solvers/Solver.scala b/src/main/scala/leon/solvers/Solver.scala
index 69551967c..f42d6ed34 100644
--- a/src/main/scala/leon/solvers/Solver.scala
+++ b/src/main/scala/leon/solvers/Solver.scala
@@ -33,7 +33,6 @@ abstract class Solver(val reporter: Reporter) extends Extension(reporter) {
     }
   }
 
-  def isUnsat(expression: Expr) : Option[Boolean] = solve(negate(expression))
   def superseeds : Seq[String] = Nil
 
   private var _forceStop = false
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index c229d44d3..e35dc8815 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -139,14 +139,12 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
     })
   }
 
-
-  override def isUnsat(vc: Expr) = decide(vc, false)
-
   def solve(vc: Expr) = decide(vc, true)
 
   override def solveOrGetCounterexample(vc : Expr) : (Option[Boolean],Map[Identifier,Expr]) = {
     restartZ3
-    decideWithModel(vc, true)
+    val (res, model, core) = decideWithModel(vc, true)
+    (res, model)
   }
 
   def decide(vc: Expr, forValidity: Boolean):Option[Boolean] = {
@@ -163,7 +161,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
     }
   }
 
-  def decideWithModel(vc: Expr, forValidity: Boolean, evaluator: Option[(Map[Identifier,Expr]) => Boolean] = None, assumptions: Option[Set[Expr]] = None): (Option[Boolean], Map[Identifier,Expr]) = {
+  private[this] def decideWithModel(vc: Expr, forValidity: Boolean, evaluator: Option[(Map[Identifier,Expr]) => Boolean] = None, assumptions: Option[Set[Expr]] = None): (Option[Boolean], Map[Identifier,Expr], Set[Expr]) = {
     val initializationStopwatch = new Stopwatch("init",               false)
     val blocking2Z3Stopwatch    = new Stopwatch("blocking-set-to-z3", false)
     val z3SearchStopwatch       = new Stopwatch("z3-search-1",        false)
@@ -193,11 +191,14 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
     foundDefinitiveAnswer = false
 
     var definitiveAnswer : Option[Boolean] = None
-    var definitiveModel : Map[Identifier,Expr] = Map.empty
-    def foundAnswer(answer : Option[Boolean], model : Map[Identifier,Expr] = Map.empty) : Unit = {
+    var definitiveModel  : Map[Identifier,Expr] = Map.empty
+    var definitiveCore   : Set[Expr] = Set.empty
+
+    def foundAnswer(answer : Option[Boolean], model : Map[Identifier,Expr] = Map.empty, core: Set[Expr] = Set.empty) : Unit = {
       foundDefinitiveAnswer = true
       definitiveAnswer = answer
-      definitiveModel = model
+      definitiveModel  = model
+      definitiveCore   = core
       //timer.foreach(t => t.halt)
     }
 
@@ -241,27 +242,28 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
       // println("Blocking set : " + blockingSet)
       blocking2Z3Stopwatch.stop
 
-      if(Settings.useCores) {
-        // NOOP
-      } else {
-        z3.push
-        if(!blockingSetAsZ3.isEmpty)
-          z3.assertCnstr(z3.mkAnd(blockingSetAsZ3 : _*))
-      }
+      z3.push
+      if(!blockingSetAsZ3.isEmpty)
+        z3.assertCnstr(z3.mkAnd(blockingSetAsZ3 : _*))
 
       reporter.info(" - Running Z3 search...")
-      val answerModelCore : (Option[Boolean], Z3Model, Seq[Z3AST]) = if(Settings.useCores) {
-        // println(blockingSetAsZ3)
-        z3.checkAssumptions(blockingSetAsZ3 : _*)
-      } else {
+      val answerModelCore : (Option[Boolean], Z3Model, Set[Expr]) = {
         z3SearchStopwatch.start
-        val (a, m, _) = assumptionsAsZ3 match {
+        val (a, m, c) = assumptionsAsZ3 match {
           case Some(as) => z3.checkAssumptions(as: _*)
           case None => val res = z3.checkAndGetModel(); (res._1, res._2, Seq.empty[Z3AST])
         }
         z3SearchStopwatch.stop
-        (a, m, Seq.empty[Z3AST])
+
+        val core: Set[Expr] = c.map(ast => fromZ3Formula(m, ast, Some(BooleanType)) match {
+          case n @ Not(Variable(_)) => n
+          case v @ Variable(_) => v
+          case _ => scala.sys.error("Impossible element extracted from core: " + ast)
+        }).toSet
+
+        (a, m, core)
       }
+
       val (answer, model, core) = answerModelCore // to work around the stupid type inferer
 
       reporter.info(" - Finished search with blocked literals")
@@ -280,10 +282,6 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
           reporter.warning("Z3 doesn't know because: " + z3.getSearchFailure.message)
           foundAnswer(None)
           m.delete
-
-          if(!Settings.useCores) {
-            z3.pop(1)
-          }
         }
         case (Some(true), m) => { // SAT
           validatingStopwatch.start
@@ -306,18 +304,9 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
             reporter.error(model)
             foundAnswer(None, model)
           }
-
-          if(!Settings.useCores) {
-            z3.pop(1)
-          }
         }
-        case (Some(false), m) if Settings.useCores && core.isEmpty => {
-          reporter.info("Empty core, definitively valid.")
-          m.delete
-          foundAnswer(Some(true))
-        }
-        case (Some(false), m) if !Settings.useCores && blockingSet.isEmpty => {
-          foundAnswer(Some(true))
+        case (Some(false), m) if blockingSet.isEmpty => {
+          foundAnswer(Some(true), core = core)
           z3.pop(1)
         }
         // This branch is both for with and without unsat cores. The
@@ -340,7 +329,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
             reporter.info(" - Finished search without blocked literals")
 
             if (result2 == Some(false)) {
-              foundAnswer(Some(true))
+              foundAnswer(Some(true), core = core)
             } else {
               luckyStopwatch.start
               Logger.debug("Model Found: " + m2, 4, "z3solver")
@@ -363,7 +352,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
             reporter.info(" - Finished search without blocked literals")
 
             if (result2 == Some(false)) {
-              foundAnswer(Some(true))
+              foundAnswer(Some(true), core = core)
             }
           }
 
@@ -376,23 +365,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
 
             unrollingStopwatch.start
 
-            val toRelease : Set[Expr] = if(Settings.useCores) {
-              unrollingCounter = unrollingCounter + 1
-              if (unrollingCounter > unrollingThreshold) {
-                reporter.info(" - Reached threshold for unrolling all blocked literals, will unroll all now.")
-                unrollingCounter = 0
-                blockingSet
-              } else {
-                // reporter.info(" - Will only unroll literals from core")
-                core.map(ast => fromZ3Formula(m, ast, Some(BooleanType)) match {
-                  case n @ Not(Variable(_)) => n
-                  case v @ Variable(_) => v
-                  case _ => scala.sys.error("Impossible element extracted from core: " + ast)
-                }).toSet
-              }
-            } else {
-              blockingSet
-            }
+            val toRelease : Set[Expr] = blockingSet
 
             // reporter.info(" - toRelease   : " + toRelease)
             // reporter.info(" - blockingSet : " + blockingSet)
@@ -478,10 +451,10 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
     validatingStopwatch.writeToSummary
 
     if(forceStop) {
-      (None, Map.empty)
+      (None, Map.empty, Set.empty)
     } else {
       assert(foundDefinitiveAnswer)
-      (definitiveAnswer, definitiveModel)
+      (definitiveAnswer, definitiveModel, definitiveCore)
     }
   }
 
diff --git a/src/main/scala/leon/testgen/CallGraph.scala b/src/main/scala/leon/testgen/CallGraph.scala
index d7169bb17..7b305d347 100644
--- a/src/main/scala/leon/testgen/CallGraph.scala
+++ b/src/main/scala/leon/testgen/CallGraph.scala
@@ -204,15 +204,15 @@ class CallGraph(val program: Program) {
 
               var testcase: Option[Map[Identifier, Expr]] = None
                 
-              val (solverResult, model) = z3Solver.decideWithModel(pc, false)
+              val (solverResult, model) = z3Solver.solveSAT(pc)
               solverResult match {
                 case None => {
                   false
                 }
-                case Some(true) => {
+                case Some(false) => {
                   false
                 }
-                case Some(false) => {
+                case Some(true) => {
                   val recPath = rec(x, xs, path ++ intermediatePath)
                   recPath match {
                     case None => false
diff --git a/src/main/scala/leon/testgen/TestGeneration.scala b/src/main/scala/leon/testgen/TestGeneration.scala
index ea6ccabcb..3b76352b2 100644
--- a/src/main/scala/leon/testgen/TestGeneration.scala
+++ b/src/main/scala/leon/testgen/TestGeneration.scala
@@ -81,15 +81,15 @@ class TestGeneration(reporter: Reporter) extends Analyser(reporter) {
         
       z3Solver.init()
       z3Solver.restartZ3
-      val (solverResult, model) = z3Solver.decideWithModel(pathCond, false)
+      val (solverResult, model) = z3Solver.solveSAT(pathCond)
 
       solverResult match {
         case None => Seq()
-        case Some(true) => {
+        case Some(false) => {
           reporter.info("The path is unreachable")
           Seq()
         }
-        case Some(false) => {
+        case Some(true) => {
           reporter.info("The model should be used as the testcase")
           Seq(model)
         }
-- 
GitLab