Skip to content

Commit

Permalink
Add test for Int<->BigInt conversions
Browse files Browse the repository at this point in the history
Also implement model extraction for BigInt,
as well as more robust model extraction for Int.
  • Loading branch information
romac committed Sep 4, 2019
1 parent e6bfc84 commit c59f14d
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 14 deletions.
42 changes: 28 additions & 14 deletions src/main/scala/z3/scala/Z3Model.scala
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
package z3.scala

import scala.util.Try
import com.microsoft.z3.Native

object Z3Model {
implicit def ast2int(model: Z3Model, ast: Z3AST): Option[Int] = {
val res = model.eval(ast)
if (res.isEmpty)
private def parseInt(str: String): Option[Int] = {
if (str.startsWith("#b"))
Try(BigInt(str.drop(2), 2).toInt).toOption
else if (str.startsWith("#x"))
Try(BigInt(str.drop(2), 16).toInt).toOption
else if (str.startsWith("#"))
None
else
model.context.getNumeralInt(res.get).value
Try(Integer.parseInt(str, 10)).toOption
}

implicit def ast2bigint(model: Z3Model, ast: Z3AST): Option[BigInt] = {
model.eval(ast) flatMap { res =>
model.context.getNumeralInt(res).value.map(BigInt(_)).orElse {
Some(BigInt(res.toString, 10))
}
}
}

implicit def ast2int(model: Z3Model, ast: Z3AST): Option[Int] = {
model.eval(ast) flatMap { res =>
model.context.getNumeralInt(res).value.orElse(parseInt(res.toString))
}
}

implicit def ast2bool(model: Z3Model, ast: Z3AST): Option[Boolean] = {
val res = model.eval(ast)
if (res.isEmpty)
None
else
model.context.getBoolValue(res.get)
model.eval(ast) flatMap { res =>
model.context.getBoolValue(res)
}
}

implicit def ast2char(model: Z3Model, ast: Z3AST): Option[Char] = {
val res = model.eval(ast)
if (res.isEmpty)
None
else
model.context.getNumeralInt(res.get).value.map(_.toChar)
model.eval(ast) flatMap { res =>
model.context.getNumeralInt(res).value.map(_.toChar)
}
}
}

Expand Down
69 changes: 69 additions & 0 deletions src/test/scala/z3/scala/IntConversions.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package z3.scala

import org.scalatest.{FunSuite, Matchers}

class IntConversions extends FunSuite with Matchers {

testIntToBigInt(0)
testIntToBigInt(42)
testIntToBigInt(-42)
testIntToBigInt(Int.MinValue)
testIntToBigInt(Int.MaxValue)

testBigIntToInt(0)
testBigIntToInt(42)
testBigIntToInt(-42)
testBigIntToInt(Int.MinValue)
testBigIntToInt(Int.MaxValue)

private def testIntToBigInt(value: Int): Unit = test(s"Int -> BigInt: $value") {
val z3 = new Z3Context("MODEL" -> true)

val Int = z3.mkIntSort
val BV32 = z3.mkBVSort(32)

val in = z3.mkConst(z3.mkStringSymbol("in"), BV32)
val out = z3.mkConst(z3.mkStringSymbol("out"), Int)

val solver = z3.mkSolver

solver.assertCnstr(z3.mkEq(in, z3.mkInt(value, BV32)))
solver.assertCnstr(z3.mkEq(out, z3.mkBV2Int(in, true)))

solver.assertCnstr(z3.mkNot(
z3.mkEq(out, z3.mkInt(value, Int))
))

val (sol, model) = solver.checkAndGetModel

(sol, model) should equal((Some(false), null))

z3.delete
}

private def testBigIntToInt(value: Int): Unit = test(s"BigInt -> Int: $value") {
val z3 = new Z3Context("MODEL" -> true)

val Int = z3.mkIntSort
val BV32 = z3.mkBVSort(32)

val in = z3.mkConst(z3.mkStringSymbol("in"), Int)
val out = z3.mkConst(z3.mkStringSymbol("out"), BV32)

val solver = z3.mkSolver

solver.assertCnstr(z3.mkEq(in, z3.mkInt(value, Int)))
solver.assertCnstr(z3.mkEq(out, z3.mkInt2BV(32, in)))

solver.assertCnstr(z3.mkNot(
z3.mkEq(out, z3.mkInt(value, BV32))
))

val (sol, model) = solver.checkAndGetModel

(sol, model) should equal((Some(false), null))

z3.delete
}
}

26 changes: 26 additions & 0 deletions src/test/scala/z3/scala/IntExtraction.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package z3.scala

import org.scalatest.{FunSuite, Matchers}

class IntExtraction extends FunSuite with Matchers {

test(s"BigInt extraction") {
val z3 = new Z3Context("MODEL" -> true)

val i = z3.mkIntSort
val x = z3.mkConst(z3.mkStringSymbol("x"), i)
val m = z3.mkInt(Int.MaxValue, i)

val solver = z3.mkSolver

solver.assertCnstr(z3.mkEq(x, z3.mkAdd(m, m)))

val (sol, model) = solver.checkAndGetModel

sol should equal(Some(true))
model.evalAs[BigInt](x) should equal(Some(BigInt(Int.MaxValue) * 2))

z3.delete
}
}

0 comments on commit c59f14d

Please sign in to comment.