From 86749646ffbef5cafa728935cb8c5214426849e9 Mon Sep 17 00:00:00 2001
From: Etienne Kneuss <ekneuss@gmail.com>
Date: Tue, 5 May 2015 14:05:11 +0200
Subject: [PATCH] Fallback to SMT solver in case native interface is
 unavailable

---
 .../scala/leon/solvers/SolverFactory.scala    | 36 +++++++++++++++++--
 .../solvers/smtlib/SMTLIBCVC4Target.scala     |  3 ++
 .../leon/solvers/smtlib/SMTLIBTarget.scala    | 27 +++++++++-----
 .../leon/solvers/smtlib/SMTLIBZ3Target.scala  |  1 +
 .../scala/leon/synthesis/Synthesizer.scala    |  2 +-
 5 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/src/main/scala/leon/solvers/SolverFactory.scala b/src/main/scala/leon/solvers/SolverFactory.scala
index 2b838b68b..5dd87da9a 100644
--- a/src/main/scala/leon/solvers/SolverFactory.scala
+++ b/src/main/scala/leon/solvers/SolverFactory.scala
@@ -40,10 +40,20 @@ object SolverFactory {
     }.mkString("")
 
   def getFromSettings(ctx: LeonContext, program: Program): SolverFactory[TimeoutSolver] = {
-    getFromName(ctx, program)(ctx.findOptionOrDefault(SharedOptions.optSelectedSolvers).toSeq : _*)
+    val names = ctx.findOptionOrDefault(SharedOptions.optSelectedSolvers)
+
+    if (((names contains "fairz3") || (names contains "unrollz3")) && !hasNativeZ3) {
+      if (!reported) {
+        ctx.reporter.warning("The Z3 native interface is not available, falling back to smt-based solver.")
+        reported = true
+      }
+      getFromName(ctx, program)("smt-z3")
+    } else {
+      getFromName(ctx, program)(names.toSeq : _*)
+    }
   }
 
-  def getFromName(ctx: LeonContext, program: Program)(names: String*): SolverFactory[TimeoutSolver] = {
+  private def getFromName(ctx: LeonContext, program: Program)(names: String*): SolverFactory[TimeoutSolver] = {
 
     def getSolver(name: String): SolverFactory[TimeoutSolver] = name match {
       case "fairz3" =>
@@ -95,9 +105,19 @@ object SolverFactory {
 
   // Solver qualifiers that get used internally:
 
+  private var reported = false
+
   // Fast solver used by simplifiactions, to discharge simple tautologies
   def uninterpreted(ctx: LeonContext, program: Program): SolverFactory[TimeoutSolver] = {
-    SolverFactory(() => new SMTLIBSolver(ctx, program) with SMTLIBZ3Target with TimeoutSolver)
+    if (hasNativeZ3) {
+      SolverFactory(() => new UninterpretedZ3Solver(ctx, program) with TimeoutSolver)
+    } else {
+      if (!reported) {
+        ctx.reporter.warning("The Z3 native interface is not available, falling back to smt-based solver.")
+        reported = true
+      }
+      SolverFactory(() => new SMTLIBSolver(ctx, program) with SMTLIBZ3Target with TimeoutSolver)
+    }
   }
 
   // Full featured solver used by default
@@ -105,4 +125,14 @@ object SolverFactory {
     getFromName(ctx, program)("fairz3")
   }
 
+  lazy val hasNativeZ3 = {
+    try {
+      new _root_.z3.scala.Z3Config
+      true
+    } catch {
+      case _: java.lang.UnsatisfiedLinkError =>
+        false
+    }
+  }
+
 }
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
index cfc0dee92..7f8d4c3e4 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
@@ -144,9 +144,12 @@ trait SMTLIBCVC4Target extends SMTLIBTarget {
       }
 
       m
+
     /**
      * ===== Set operations =====
      */
+
+
     case fs @ FiniteSet(elems) =>
       if (elems.isEmpty) {
         QualifiedIdentifier(SMTIdentifier(SSymbol("emptyset")), Some(declareSort(fs.getType)))
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
index fcfe4c801..7d694d10d 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
@@ -57,12 +57,13 @@ trait SMTLIBTarget {
   def id2sym(id: Identifier): SSymbol = SSymbol(id.name+"!"+id.globalId)
 
   // metadata for CC, and variables
-  val constructors = new IncrementalBijection[TypeTree, SSymbol]()
-  val selectors    = new IncrementalBijection[(TypeTree, Int), SSymbol]()
-  val testers      = new IncrementalBijection[TypeTree, SSymbol]()
-  val variables    = new IncrementalBijection[Identifier, SSymbol]()
-  val sorts        = new IncrementalBijection[TypeTree, Sort]()
-  val functions    = new IncrementalBijection[TypedFunDef, SSymbol]()
+  val constructors  = new IncrementalBijection[TypeTree, SSymbol]()
+  val selectors     = new IncrementalBijection[(TypeTree, Int), SSymbol]()
+  val testers       = new IncrementalBijection[TypeTree, SSymbol]()
+  val variables     = new IncrementalBijection[Identifier, SSymbol]()
+  val genericValues = new IncrementalBijection[GenericValue, SSymbol]()
+  val sorts         = new IncrementalBijection[TypeTree, Sort]()
+  val functions     = new IncrementalBijection[TypedFunDef, SSymbol]()
 
   protected object OptionManager {
     lazy val leonOption = program.library.Option.get
@@ -151,7 +152,8 @@ trait SMTLIBTarget {
 
   def fromRawArray(r: RawArrayValue, tpe: TypeTree): Expr = tpe match {
     case SetType(base) =>
-      require(r.default == BooleanLiteral(false) && r.keyTpe == base)
+      require(r.default == BooleanLiteral(false), "Co-finite sets are not supported.")
+      require(r.keyTpe == base, s"Type error in solver model, expected $base, found ${r.keyTpe}")
 
       finiteSet(r.elems.keySet, base)
 
@@ -512,6 +514,12 @@ trait SMTLIBTarget {
       case m : MatchExpr =>
         toSMT(matchToIfThenElse(m))
 
+
+      case gv @ GenericValue(tpe, n) =>
+        genericValues.cachedB(gv) {
+          declareVariable(FreshIdentifier("gv"+n, tpe))
+        }
+
       /**
        * ===== Everything else =====
        */
@@ -582,7 +590,8 @@ trait SMTLIBTarget {
           case _ => reporter.fatalError("Unhandled nary "+e)
         }
 
-      case o => unsupported("Tree: " + o)
+      case o =>
+        unsupported("Tree: " + o)
     }
   }
 
@@ -731,6 +740,7 @@ trait SMTLIBTarget {
     selectors.push()
     testers.push()
     variables.push()
+    genericValues.push()
     sorts.push()
     functions.push()
 
@@ -744,6 +754,7 @@ trait SMTLIBTarget {
     selectors.pop()
     testers.pop()
     variables.pop()
+    genericValues.pop()
     sorts.pop()
     functions.pop()
 
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
index 47088d817..1574e990b 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
@@ -41,6 +41,7 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
     sorts.cachedB(tpe) {
       tpe match {
         case SetType(base) =>
+          super.declareSort(BooleanType)
           declareSetSort(base)
         case _ =>
           super.declareSort(t)
diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala
index 9dabc1233..40e6b8bbc 100644
--- a/src/main/scala/leon/synthesis/Synthesizer.scala
+++ b/src/main/scala/leon/synthesis/Synthesizer.scala
@@ -73,7 +73,7 @@ class Synthesizer(val context : LeonContext,
 
     val (npr, fds) = solutionToProgram(sol)
 
-    val solverf = SolverFactory.getFromName(context, npr)("fairz3").withTimeout(timeout)
+    val solverf = SolverFactory.default(context, npr).withTimeout(timeout)
 
     val vctx = VerificationContext(context, npr, solverf, context.reporter)
     val vcs = generateVCs(vctx, Some(fds.map(_.id.name)))
-- 
GitLab