Skip to content

Commit 6f915ca

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 6f915ca

File tree

3 files changed

+120
-14
lines changed

3 files changed

+120
-14
lines changed

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

+28-14
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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
solver.assertCnstr(z3.mkEq(out, z3.mkInt(value, Int)))
33+
34+
val (sol, model) = solver.checkAndGetModel
35+
36+
sol should equal(Some(true))
37+
model.evalAs[BigInt](out) should equal(Some(BigInt(value)))
38+
39+
z3.delete
40+
}
41+
42+
private def testBigIntToInt(value: Int): Unit = test(s"BigInt -> Int: $value") {
43+
val z3 = new Z3Context("MODEL" -> true)
44+
45+
val Int = z3.mkIntSort
46+
val BV32 = z3.mkBVSort(32)
47+
48+
val in = z3.mkConst(z3.mkStringSymbol("in"), Int)
49+
val out = z3.mkConst(z3.mkStringSymbol("out"), BV32)
50+
51+
val solver = z3.mkSolver
52+
53+
solver.assertCnstr(z3.mkEq(in, z3.mkInt(value, Int)))
54+
solver.assertCnstr(z3.mkEq(out, z3.mkInt2BV(32, in)))
55+
solver.assertCnstr(z3.mkEq(out, z3.mkInt(value, BV32)))
56+
57+
val (sol, model) = solver.checkAndGetModel
58+
59+
sol should equal(Some(true))
60+
model.evalAs[Int](out) should equal(Some(value))
61+
62+
z3.delete
63+
}
64+
}
65+
66+
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)