Skip to content

Commit c59f14d

Browse files
committed
Add test for Int<->BigInt conversions
Also implement model extraction for BigInt, as well as more robust model extraction for Int.
1 parent e6bfc84 commit c59f14d

File tree

3 files changed

+123
-14
lines changed

3 files changed

+123
-14
lines changed

src/main/scala/z3/scala/Z3Model.scala

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,44 @@
11
package z3.scala
22

3+
import scala.util.Try
34
import com.microsoft.z3.Native
45

56
object Z3Model {
6-
implicit def ast2int(model: Z3Model, ast: Z3AST): Option[Int] = {
7-
val res = model.eval(ast)
8-
if (res.isEmpty)
7+
private def parseInt(str: String): Option[Int] = {
8+
if (str.startsWith("#b"))
9+
Try(BigInt(str.drop(2), 2).toInt).toOption
10+
else if (str.startsWith("#x"))
11+
Try(BigInt(str.drop(2), 16).toInt).toOption
12+
else if (str.startsWith("#"))
913
None
1014
else
11-
model.context.getNumeralInt(res.get).value
15+
Try(Integer.parseInt(str, 10)).toOption
16+
}
17+
18+
implicit def ast2bigint(model: Z3Model, ast: Z3AST): Option[BigInt] = {
19+
model.eval(ast) flatMap { res =>
20+
model.context.getNumeralInt(res).value.map(BigInt(_)).orElse {
21+
Some(BigInt(res.toString, 10))
22+
}
23+
}
24+
}
25+
26+
implicit def ast2int(model: Z3Model, ast: Z3AST): Option[Int] = {
27+
model.eval(ast) flatMap { res =>
28+
model.context.getNumeralInt(res).value.orElse(parseInt(res.toString))
29+
}
1230
}
1331

1432
implicit def ast2bool(model: Z3Model, ast: Z3AST): Option[Boolean] = {
15-
val res = model.eval(ast)
16-
if (res.isEmpty)
17-
None
18-
else
19-
model.context.getBoolValue(res.get)
33+
model.eval(ast) flatMap { res =>
34+
model.context.getBoolValue(res)
35+
}
2036
}
2137

2238
implicit def ast2char(model: Z3Model, ast: Z3AST): Option[Char] = {
23-
val res = model.eval(ast)
24-
if (res.isEmpty)
25-
None
26-
else
27-
model.context.getNumeralInt(res.get).value.map(_.toChar)
39+
model.eval(ast) flatMap { res =>
40+
model.context.getNumeralInt(res).value.map(_.toChar)
41+
}
2842
}
2943
}
3044

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package z3.scala
2+
3+
import org.scalatest.{FunSuite, Matchers}
4+
5+
class IntConversions extends FunSuite with Matchers {
6+
7+
testIntToBigInt(0)
8+
testIntToBigInt(42)
9+
testIntToBigInt(-42)
10+
testIntToBigInt(Int.MinValue)
11+
testIntToBigInt(Int.MaxValue)
12+
13+
testBigIntToInt(0)
14+
testBigIntToInt(42)
15+
testBigIntToInt(-42)
16+
testBigIntToInt(Int.MinValue)
17+
testBigIntToInt(Int.MaxValue)
18+
19+
private def testIntToBigInt(value: Int): Unit = test(s"Int -> BigInt: $value") {
20+
val z3 = new Z3Context("MODEL" -> true)
21+
22+
val Int = z3.mkIntSort
23+
val BV32 = z3.mkBVSort(32)
24+
25+
val in = z3.mkConst(z3.mkStringSymbol("in"), BV32)
26+
val out = z3.mkConst(z3.mkStringSymbol("out"), Int)
27+
28+
val solver = z3.mkSolver
29+
30+
solver.assertCnstr(z3.mkEq(in, z3.mkInt(value, BV32)))
31+
solver.assertCnstr(z3.mkEq(out, z3.mkBV2Int(in, true)))
32+
33+
solver.assertCnstr(z3.mkNot(
34+
z3.mkEq(out, z3.mkInt(value, Int))
35+
))
36+
37+
val (sol, model) = solver.checkAndGetModel
38+
39+
(sol, model) should equal((Some(false), null))
40+
41+
z3.delete
42+
}
43+
44+
private def testBigIntToInt(value: Int): Unit = test(s"BigInt -> Int: $value") {
45+
val z3 = new Z3Context("MODEL" -> true)
46+
47+
val Int = z3.mkIntSort
48+
val BV32 = z3.mkBVSort(32)
49+
50+
val in = z3.mkConst(z3.mkStringSymbol("in"), Int)
51+
val out = z3.mkConst(z3.mkStringSymbol("out"), BV32)
52+
53+
val solver = z3.mkSolver
54+
55+
solver.assertCnstr(z3.mkEq(in, z3.mkInt(value, Int)))
56+
solver.assertCnstr(z3.mkEq(out, z3.mkInt2BV(32, in)))
57+
58+
solver.assertCnstr(z3.mkNot(
59+
z3.mkEq(out, z3.mkInt(value, BV32))
60+
))
61+
62+
val (sol, model) = solver.checkAndGetModel
63+
64+
(sol, model) should equal((Some(false), null))
65+
66+
z3.delete
67+
}
68+
}
69+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package z3.scala
2+
3+
import org.scalatest.{FunSuite, Matchers}
4+
5+
class IntExtraction extends FunSuite with Matchers {
6+
7+
test(s"BigInt extraction") {
8+
val z3 = new Z3Context("MODEL" -> true)
9+
10+
val i = z3.mkIntSort
11+
val x = z3.mkConst(z3.mkStringSymbol("x"), i)
12+
val m = z3.mkInt(Int.MaxValue, i)
13+
14+
val solver = z3.mkSolver
15+
16+
solver.assertCnstr(z3.mkEq(x, z3.mkAdd(m, m)))
17+
18+
val (sol, model) = solver.checkAndGetModel
19+
20+
sol should equal(Some(true))
21+
model.evalAs[BigInt](x) should equal(Some(BigInt(Int.MaxValue) * 2))
22+
23+
z3.delete
24+
}
25+
}
26+

0 commit comments

Comments
 (0)