From 0ad6920486c6f8a3c438536e09092f3023d9a879 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com>
Date: Thu, 9 Jun 2011 22:14:55 +0000
Subject: [PATCH] changed interface of Solver to prevent halt before solve
 problem. Added a init method to be called before solve

---
 src/multisets/Main.scala           |  6 ------
 src/orderedsets/Main.scala         |  5 -----
 src/orderedsets/UnifierMain.scala  |  5 -----
 src/purescala/Analysis.scala       |  1 +
 src/purescala/Extensions.scala     | 13 ++++++++++---
 src/purescala/FairZ3Solver.scala   | 10 ++++------
 src/purescala/ParallelSolver.scala | 27 ++++++++++++++++++++-------
 src/purescala/RandomSolver.scala   | 16 ++++------------
 src/purescala/TimeoutSolver.scala  |  7 +++++--
 src/purescala/Timer.scala          |  1 +
 src/purescala/TrivialSolver.scala  |  3 ---
 src/purescala/Z3Solver.scala       |  4 ----
 12 files changed, 45 insertions(+), 53 deletions(-)

diff --git a/src/multisets/Main.scala b/src/multisets/Main.scala
index af0c03690..6019d42cf 100644
--- a/src/multisets/Main.scala
+++ b/src/multisets/Main.scala
@@ -12,12 +12,6 @@ class Main(reporter: Reporter) extends Solver(reporter) {
   val description = "Multiset Solver"
   Global.reporter = reporter
 
-  //TODO
-  def halt() {
-    error("TODO halt in multiset Solver")
-  }
-
-
   def createFormulaThatSomethingsIsSet(s:String):FormulaIn = {
     val a1 = FIAtom(AIEq(TIMultiplicity(s), TIConstant(1)))
     val a0 = FIAtom(AIEq(TIMultiplicity(s), TIConstant(0)))
diff --git a/src/orderedsets/Main.scala b/src/orderedsets/Main.scala
index c9cf22d8b..e338e059a 100644
--- a/src/orderedsets/Main.scala
+++ b/src/orderedsets/Main.scala
@@ -13,11 +13,6 @@ class Main(reporter: Reporter) extends Solver(reporter) {
   val description = "BAPA with ordering"
   override val shortDescription = "BAPA<"
 
-  //TODO
-  def halt() {
-    error("TODO halt in multiset Solver")
-  }
-
   // checks for V-A-L-I-D-I-T-Y !
   // Some(true) means formula is valid (negation is unsat)
   // Some(false) means formula is not valid (negation is sat)
diff --git a/src/orderedsets/UnifierMain.scala b/src/orderedsets/UnifierMain.scala
index f512759ed..eec35bcd2 100644
--- a/src/orderedsets/UnifierMain.scala
+++ b/src/orderedsets/UnifierMain.scala
@@ -26,11 +26,6 @@ class UnifierMain(reporter: Reporter) extends Solver(reporter) {
 
   var program: Program = null
 
-  //TODO
-  def halt() {
-    error("TODO halt in multiset Solver")
-  }
-
   override def setProgram(p: Program) = program = p
 
   // checks for V-A-L-I-D-I-T-Y !
diff --git a/src/purescala/Analysis.scala b/src/purescala/Analysis.scala
index 5fe5ce718..7f2bfad06 100644
--- a/src/purescala/Analysis.scala
+++ b/src/purescala/Analysis.scala
@@ -98,6 +98,7 @@ class Analysis(val program: Program, val reporter: Reporter = Settings.reporter)
           superseeded = superseeded ++ Set(se.superseeds: _*)
 
           val t1 = System.nanoTime
+          se.init()
           val solverResult = se.solve(vc)
           val t2 = System.nanoTime
           val dt = ((t2 - t1) / 1000000) / 1000.0
diff --git a/src/purescala/Extensions.scala b/src/purescala/Extensions.scala
index a5618f64b..2653bffab 100644
--- a/src/purescala/Extensions.scala
+++ b/src/purescala/Extensions.scala
@@ -17,14 +17,21 @@ object Extensions {
 
     // Returns Some(true) if valid, Some(false) if invalid,
     // None if unknown.
+    // should halt as soon as possible with any result (Unknown is ok) as soon as forceStop is true
     def solve(expression: Expr) : Option[Boolean]
 
     def isUnsat(expression: Expr) : Option[Boolean] = solve(negate(expression))
     def superseeds : Seq[String] = Nil
 
-    //once this is called, the solver should halt and return a value (probably Unknown) from the
-    //solve method as soon as possible
-    def halt() : Unit
+    private var _forceStop = false
+    def halt() : Unit = {
+      _forceStop = true
+    }
+    def init() : Unit = {
+      _forceStop = false
+    }
+    protected def forceStop = _forceStop
+
   }
   
   abstract class Analyser(reporter: Reporter) extends Extension(reporter) {
diff --git a/src/purescala/FairZ3Solver.scala b/src/purescala/FairZ3Solver.scala
index 28ed00ec0..ca20e8d9a 100644
--- a/src/purescala/FairZ3Solver.scala
+++ b/src/purescala/FairZ3Solver.scala
@@ -414,11 +414,10 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
     decideWithModel(vc, forValidity)._1
   }
 
-  private var forceStop : Boolean = false
   private var foundDefinitiveAnswer : Boolean = false
-  def halt() {
+  override def halt() {
     if(!foundDefinitiveAnswer) {
-      forceStop = true
+      super.halt
       if(z3 != null)
         z3.softCheckCancel
     }
@@ -438,16 +437,15 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
 
     initializationStopwatch.start
 
-    forceStop = false
-
     foundDefinitiveAnswer = false
+    /*
     def stopCallback() : Unit = {
       if(!foundDefinitiveAnswer) {
         reporter.error(" - Timeout reached.")
         forceStop = true
         z3.softCheckCancel
       }
-    }
+    }*/
 
     //val timer : Option[Timer] = Settings.solverTimeout.map(t => new Timer(stopCallback, t))
     //timer.foreach(_.start())
diff --git a/src/purescala/ParallelSolver.scala b/src/purescala/ParallelSolver.scala
index 8870d10c4..63b04c76c 100644
--- a/src/purescala/ParallelSolver.scala
+++ b/src/purescala/ParallelSolver.scala
@@ -1,8 +1,5 @@
 package purescala
 
-//TODO: what if we call halt before solve is started in every solvers
-//TODO: stopping the FairZ3Solver seems to cause an error because model is not correct
-
 import Common._
 import Definitions._
 import Extensions._
@@ -26,9 +23,11 @@ class ParallelSolver(solvers: Solver*) extends Solver(solvers(0).reporter) {
   override val superseeds : Seq[String] = solvers.map(_.shortDescription).toSeq
 
   case class Solve(expr: Expr)
+  case object Init
+  case object Ready
   case class Result(res: Option[Boolean])
 
-  class SolverRunner(s: Solver) extends DaemonActor {
+  private class SolverRunner(s: Solver) extends DaemonActor {
 
     /*
     val that = this
@@ -51,6 +50,11 @@ class ParallelSolver(solvers: Solver*) extends Solver(solvers(0).reporter) {
     def act(): Unit = {
       while(true) {
         receive {
+          case Init => {
+            reporter.info("Init solver " + s.shortDescription)
+            s.init 
+            coordinator ! Ready
+          }
           case Solve(expr) => {
             reporter.info("Starting solver " + s.shortDescription)
             val res = s.solve(expr)
@@ -62,15 +66,24 @@ class ParallelSolver(solvers: Solver*) extends Solver(solvers(0).reporter) {
     }
   }
 
-  class Coordinator extends DaemonActor {
+  private class Coordinator extends DaemonActor {
 
     def act(): Unit = {
       while(true) {
         receive {
           case s@Solve(expr) => {
+            var nbResponses = 0
+
+            solverRunners.foreach(_ ! Init)
+            while(nbResponses < nbSolvers) {
+              receive {
+                case Ready => nbResponses += 1
+              }
+            }
+
+            nbResponses = 0
             solverRunners.foreach(_ ! s)
             var result: Option[Boolean] = None
-            var nbResponses = 0
 
             while(nbResponses < nbSolvers) {
               receive {
@@ -101,7 +114,7 @@ class ParallelSolver(solvers: Solver*) extends Solver(solvers(0).reporter) {
     result
   }
 
-  def halt() {
+  override def halt() {
     solvers.foreach(_.halt)
   }
 
diff --git a/src/purescala/RandomSolver.scala b/src/purescala/RandomSolver.scala
index 6bf72bed3..18623a5f7 100644
--- a/src/purescala/RandomSolver.scala
+++ b/src/purescala/RandomSolver.scala
@@ -64,19 +64,11 @@ class RandomSolver(reporter: Reporter, val nbTrial: Option[Int] = None) extends
     case f : FunctionType => error("I don't know what to do")
   }
 
-  private var externalRunning = true
-
-  def halt() {
-    externalRunning = false
-  }
-
   def solve(expression: Expr) : Option[Boolean] = {
     val vars = variablesOf(expression)
     val nbVars = vars.size
 
-    var running = true
-    externalRunning = true
-
+    var stop = false
     //bound starts at 1 since it allows to test value like 0, 1, and Leaf of class hierarchy
     var bound = 1
     val maxBound = Int.MaxValue
@@ -86,10 +78,10 @@ class RandomSolver(reporter: Reporter, val nbTrial: Option[Int] = None) extends
 
     var result: Option[Boolean] = None
     var iteration = 0
-    while(running && externalRunning) {
+    while(!forceStop && !stop) {
 
       nbTrial match {
-        case Some(n) => running &&= (iteration < n)
+        case Some(n) => stop &&= (iteration < n)
         case None => ()
       }
 
@@ -112,7 +104,7 @@ class RandomSolver(reporter: Reporter, val nbTrial: Option[Int] = None) extends
         case OK(BooleanLiteral(false)) => {
           reporter.info("Found counter example to formula: " + var2val)
           result = Some(false)
-          running = false
+          stop = true
         }
         /* in any of the following case, simply continue with another assignement */
         case InfiniteComputation() => {
diff --git a/src/purescala/TimeoutSolver.scala b/src/purescala/TimeoutSolver.scala
index aa1e28424..dcd2a95ad 100644
--- a/src/purescala/TimeoutSolver.scala
+++ b/src/purescala/TimeoutSolver.scala
@@ -11,7 +11,7 @@ import scala.sys.error
 class TimeoutSolver(solver : Solver, timeout : Int) extends Solver(solver.reporter) {
 
   val description = solver.description + ", with timeout"
-  override val shortDescription = solver.shortDescription
+  override val shortDescription = solver.shortDescription + "+t"
 
   override def setProgram(prog: Program): Unit = {
     solver.setProgram(prog)
@@ -25,7 +25,10 @@ class TimeoutSolver(solver : Solver, timeout : Int) extends Solver(solver.report
     res
   }
 
-  def halt() {
+  override def init() {
+    solver.init
+  }
+  override def halt() {
     solver.halt
   }
 
diff --git a/src/purescala/Timer.scala b/src/purescala/Timer.scala
index 0579c93fa..b72b12b3e 100644
--- a/src/purescala/Timer.scala
+++ b/src/purescala/Timer.scala
@@ -14,6 +14,7 @@ class Timer(callback : () => Unit, maxSecs : Int) extends Thread {
       if(asMillis < (System.currentTimeMillis - startTime)) {
         exceeded = true
       }
+      Thread.sleep(100) //is needed on my (regis) machine, if not here, the loop does not stop when halt is called.
     }
     if(exceeded && keepRunning) {
       callback()
diff --git a/src/purescala/TrivialSolver.scala b/src/purescala/TrivialSolver.scala
index cef3ca8b6..78cf3d0ef 100644
--- a/src/purescala/TrivialSolver.scala
+++ b/src/purescala/TrivialSolver.scala
@@ -19,7 +19,4 @@ class TrivialSolver(reporter: Reporter) extends Solver(reporter) {
     case _ => None
   }
 
-  def halt() {
-    //nothing to do
-  }
 }
diff --git a/src/purescala/Z3Solver.scala b/src/purescala/Z3Solver.scala
index 75350ff97..98cb563b4 100644
--- a/src/purescala/Z3Solver.scala
+++ b/src/purescala/Z3Solver.scala
@@ -49,10 +49,6 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3Solve
     program = prog
   }
 
-  def halt() {
-    scala.sys.error("Halt not supported")
-  }
-
   private def restartZ3: Unit = {
     if (neverInitialized) {
       neverInitialized = false
-- 
GitLab