From 6572e27714f9c70cab3b3224a2f5cf7bfda9b032 Mon Sep 17 00:00:00 2001
From: Nicolas Voirol <voirol.nicolas@gmail.com>
Date: Sat, 26 Mar 2016 16:45:07 +0100
Subject: [PATCH] Termination checker fixes for new DefOps and theory encoders

---
 src/main/scala/leon/purescala/DefOps.scala    |  8 ++++---
 .../solvers/cvc4/CVC4UnrollingSolver.scala    |  2 +-
 .../solvers/smtlib/SMTLIBCVC4Solver.scala     |  5 ++++-
 .../leon/solvers/smtlib/SMTLIBSolver.scala    |  2 +-
 .../leon/solvers/smtlib/SMTLIBZ3Solver.scala  |  3 ++-
 .../leon/solvers/theories/BagEncoder.scala    |  2 +-
 .../leon/solvers/theories/StringEncoder.scala |  2 +-
 .../leon/solvers/theories/TheoryEncoder.scala |  2 +-
 .../solvers/unrolling/UnrollingSolver.scala   |  9 ++++----
 .../scala/leon/solvers/z3/FairZ3Solver.scala  |  2 +-
 .../leon/solvers/z3/Z3UnrollingSolver.scala   |  2 +-
 .../leon/termination/ChainProcessor.scala     |  6 ++---
 .../scala/leon/termination/Processor.scala    | 22 +++++++------------
 13 files changed, 34 insertions(+), 33 deletions(-)

diff --git a/src/main/scala/leon/purescala/DefOps.scala b/src/main/scala/leon/purescala/DefOps.scala
index 7f0e5b018..753b0944c 100644
--- a/src/main/scala/leon/purescala/DefOps.scala
+++ b/src/main/scala/leon/purescala/DefOps.scala
@@ -357,7 +357,7 @@ object DefOps {
     })
 
     for (cd <- p.definedClasses if requiresReplacement(cd)) trCd(cd)
-    for (fd <- p.definedFunctions if requiresReplacement(fd)) {
+    for (fd <- p.definedFunctions if requiresReplacement(fd) && !(fdMap contains fd)) {
       val newId = transformer.transform(fd.id)
       val newReturn = transformer.transform(fd.returnType)
       val newParams = fd.params map (vd => ValDef(transformer.transform(vd.id)))
@@ -372,8 +372,10 @@ object DefOps {
     }
 
     for ((fd,nfd) <- fdMap) {
-      val bindings = (fd.params zip nfd.params).map(p => p._1.id -> p._2.id).toMap
-      nfd.fullBody = transformer.transform(fd.fullBody)(bindings)
+      val bindings = (fd.params zip nfd.params).map(p => p._1.id -> p._2.id).toMap ++
+        nfd.params.map(vd => vd.id -> vd.id)
+
+      nfd.fullBody = transformer.transform(nfd.fullBody)(bindings)
     }
 
     val fdsMap = fdMap.toMap
diff --git a/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala b/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala
index 79498f97b..3ddfca8d9 100644
--- a/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/cvc4/CVC4UnrollingSolver.scala
@@ -10,4 +10,4 @@ import unrolling._
 import theories._
 
 class CVC4UnrollingSolver(context: LeonContext, program: Program, underlying: Solver)
-  extends UnrollingSolver(context, program, underlying, theories = NoEncoder)
+  extends UnrollingSolver(context, program, underlying, theories = new NoEncoder)
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala
index 4c17f8089..5de74510b 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Solver.scala
@@ -5,9 +5,12 @@ package solvers.smtlib
 
 import OptionParsers._
 
+import solvers.theories._
 import purescala.Definitions.Program
 
-class SMTLIBCVC4Solver(context: LeonContext, program: Program) extends SMTLIBSolver(context, program) with SMTLIBCVC4Target {
+class SMTLIBCVC4Solver(context: LeonContext, program: Program)
+  extends SMTLIBSolver(context, program, new NoEncoder)
+     with SMTLIBCVC4Target {
 
   def targetName = "cvc4"
 
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
index 99e107027..9f6f92b93 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
@@ -16,7 +16,7 @@ import _root_.smtlib.parser.CommandsResponses.{Error => ErrorResponse, _}
 import theories._
 import utils._
 
-abstract class SMTLIBSolver(val context: LeonContext, val program: Program, theories: TheoryEncoder = NoEncoder) 
+abstract class SMTLIBSolver(val context: LeonContext, val program: Program, theories: TheoryEncoder)
                            extends Solver with SMTLIBTarget with NaiveAssumptionSolver {
 
   /* Solver name */
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
index e12b53fb5..6a58f9f1a 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
@@ -16,7 +16,8 @@ import _root_.smtlib.theories.Core.{Equals => _, _}
 import theories._
 
 class SMTLIBZ3Solver(context: LeonContext, program: Program)
-  extends SMTLIBSolver(context, program, StringEncoder) with SMTLIBZ3Target {
+  extends SMTLIBSolver(context, program, new StringEncoder)
+     with SMTLIBZ3Target {
 
   def getProgram: Program = program
 }
diff --git a/src/main/scala/leon/solvers/theories/BagEncoder.scala b/src/main/scala/leon/solvers/theories/BagEncoder.scala
index fb6674224..4ba7fcaa4 100644
--- a/src/main/scala/leon/solvers/theories/BagEncoder.scala
+++ b/src/main/scala/leon/solvers/theories/BagEncoder.scala
@@ -8,7 +8,7 @@ import purescala.Common._
 import purescala.Expressions._
 import purescala.Types._
 
-object BagEncoder extends TheoryEncoder {
+class BagEncoder(val context: LeonContext) extends TheoryEncoder {
   val encoder = new Encoder
   val decoder = new Decoder
 }
diff --git a/src/main/scala/leon/solvers/theories/StringEncoder.scala b/src/main/scala/leon/solvers/theories/StringEncoder.scala
index f8b55303b..8f33513a6 100644
--- a/src/main/scala/leon/solvers/theories/StringEncoder.scala
+++ b/src/main/scala/leon/solvers/theories/StringEncoder.scala
@@ -116,7 +116,7 @@ object StringEcoSystem {
   val funDefs = Seq(StringSize, StringListConcat, StringTake, StringDrop, StringSlice)
 }
 
-object StringEncoder extends TheoryEncoder {
+class StringEncoder extends TheoryEncoder {
   import StringEcoSystem._
 
   private val stringBijection = new Bijection[String, Expr]()
diff --git a/src/main/scala/leon/solvers/theories/TheoryEncoder.scala b/src/main/scala/leon/solvers/theories/TheoryEncoder.scala
index 9cb18effd..39b5a632c 100644
--- a/src/main/scala/leon/solvers/theories/TheoryEncoder.scala
+++ b/src/main/scala/leon/solvers/theories/TheoryEncoder.scala
@@ -75,7 +75,7 @@ trait TheoryEncoder { self =>
   }
 }
 
-object NoEncoder extends TheoryEncoder {
+class NoEncoder extends TheoryEncoder {
   val encoder = new Encoder
   val decoder = new Decoder
 }
diff --git a/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala b/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala
index 76f18864b..852e125ed 100644
--- a/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/unrolling/UnrollingSolver.scala
@@ -394,10 +394,11 @@ trait AbstractUnrollingSolver[T]
                 }
 
                 if (!foundDefinitiveAnswer) {
-                  unrollingBank.decreaseAllGenerations()
+                  val promote = templateGenerator.manager.getBlockersToPromote(model.eval)
+                  if (promote.nonEmpty) {
+                    unrollingBank.decreaseAllGenerations()
 
-                  for (b <- templateGenerator.manager.getBlockersToPromote(model.eval)) {
-                    unrollingBank.promoteBlocker(b, force = true)
+                    for (b <- promote) unrollingBank.promoteBlocker(b, force = true)
                   }
                 }
               }
@@ -449,7 +450,7 @@ class UnrollingSolver(
   val context: LeonContext,
   val program: Program,
   underlying: Solver,
-  theories: TheoryEncoder = NoEncoder
+  theories: TheoryEncoder = new NoEncoder
 ) extends AbstractUnrollingSolver[Expr] {
 
   override val name = "U:"+underlying.name
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index 7c79597f2..f8237a488 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -103,7 +103,7 @@ class FairZ3Solver(val context: LeonContext, val program: Program)
     def asString(implicit ctx: LeonContext) = z3.toString
   }
 
-  val theoryEncoder = StringEncoder
+  val theoryEncoder = new StringEncoder
 
   val templateEncoder = new TemplateEncoder[Z3AST] {
     def encodeId(id: Identifier): Z3AST = {
diff --git a/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala b/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala
index ec1428e39..99c75199a 100644
--- a/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/z3/Z3UnrollingSolver.scala
@@ -10,4 +10,4 @@ import unrolling._
 import theories._
 
 class Z3UnrollingSolver(context: LeonContext, program: Program, underlying: Solver)
-  extends UnrollingSolver(context, program, underlying, theories = StringEncoder)
+  extends UnrollingSolver(context, program, underlying, theories = new StringEncoder)
diff --git a/src/main/scala/leon/termination/ChainProcessor.scala b/src/main/scala/leon/termination/ChainProcessor.scala
index c01fa9fb3..ef6fde2e2 100644
--- a/src/main/scala/leon/termination/ChainProcessor.scala
+++ b/src/main/scala/leon/termination/ChainProcessor.scala
@@ -58,11 +58,11 @@ class ChainProcessor(
       if (structuralDecreasing || numericDecreasing)
         Some(problem.funDefs map Cleared)
       else {
-        val chainsUnlooping = chains.flatMap(c1 => chains.flatMap(c2 => c1 compose c2)).forall {
-          chain => !definitiveSATwithModel(andJoin(chain.loop())).isDefined
+        val maybeReentrant = chains.flatMap(c1 => chains.flatMap(c2 => c1 compose c2)).exists {
+          chain => maybeSAT(andJoin(chain.loop()))
         }
 
-        if (chainsUnlooping) 
+        if (!maybeReentrant)
           Some(problem.funDefs map Cleared)
         else 
           None
diff --git a/src/main/scala/leon/termination/Processor.scala b/src/main/scala/leon/termination/Processor.scala
index 1d0527127..6f998b0ed 100644
--- a/src/main/scala/leon/termination/Processor.scala
+++ b/src/main/scala/leon/termination/Processor.scala
@@ -34,7 +34,7 @@ trait Solvable extends Processor {
     val sizeUnit    : UnitDef     = UnitDef(FreshIdentifier("$size"),Seq(sizeModule)) 
     val newProgram  : Program     = program.copy( units = sizeUnit :: program.units)
 
-    SolverFactory.getFromSettings(context, newProgram).withTimeout(10.seconds)
+    SolverFactory.getFromSettings(context, newProgram).withTimeout(1.seconds)
   }
 
   type Solution = (Option[Boolean], Map[Identifier, Expr])
@@ -52,23 +52,17 @@ trait Solvable extends Processor {
     res
   }
 
-  def maybeSAT(problem: Expr): Boolean = {
-    withoutPosts {
-      SimpleSolverAPI(solver).solveSAT(problem)._1 getOrElse true
-    }
+  def maybeSAT(problem: Expr): Boolean = withoutPosts {
+    SimpleSolverAPI(solver).solveSAT(problem)._1 getOrElse true
   }
 
-  def definitiveALL(problem: Expr): Boolean = {
-    withoutPosts {
-      SimpleSolverAPI(solver).solveSAT(Not(problem))._1.exists(!_)
-    }
+  def definitiveALL(problem: Expr): Boolean = withoutPosts {
+    SimpleSolverAPI(solver).solveSAT(Not(problem))._1.exists(!_)
   }
 
-  def definitiveSATwithModel(problem: Expr): Option[Model] = {
-    withoutPosts {
-      val (sat, model) = SimpleSolverAPI(solver).solveSAT(problem)
-      if (sat.isDefined && sat.get) Some(model) else None
-    }
+  def definitiveSATwithModel(problem: Expr): Option[Model] = withoutPosts {
+    val (sat, model) = SimpleSolverAPI(solver).solveSAT(problem)
+    if (sat.isDefined && sat.get) Some(model) else None
   }
 }
 
-- 
GitLab