Skip to content

Commit 856cbfe

Browse files
authored
Fix int division (#119)
* cvc: fix int division * core: fix int division rounding
1 parent fe68394 commit 856cbfe

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/ArithSimplificationRules.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ inline fun <T : KArithSort> KContext.simplifyArithDivLight(
174174
}
175175

176176
if (lhs is KIntNumExpr) {
177-
return mkIntNum(lhs.bigIntegerValue / rValue.numerator).uncheckedCast()
177+
return mkIntNum(evalIntDiv(lhs.bigIntegerValue, rValue.numerator)).uncheckedCast()
178178
}
179179

180180
if (lhs is KRealNumExpr) {
@@ -407,6 +407,26 @@ fun <T : KArithSort> KExpr<T>.toRealValue(): RealValue? = when (this) {
407407
else -> null
408408
}
409409

410+
/**
411+
* Eval integer div wrt Int theory rules.
412+
* */
413+
fun evalIntDiv(a: BigInteger, b: BigInteger): BigInteger {
414+
if (a >= BigInteger.ZERO) {
415+
return a / b
416+
}
417+
val (divisionRes, rem) = a.divideAndRemainder(b)
418+
if (rem == BigInteger.ZERO) {
419+
return divisionRes
420+
}
421+
422+
// round toward zero
423+
return if (b >= BigInteger.ZERO) {
424+
divisionRes - BigInteger.ONE
425+
} else {
426+
divisionRes + BigInteger.ONE
427+
}
428+
}
429+
410430
/**
411431
* Eval integer mod wrt Int theory rules.
412432
* */

ksmt-core/src/test/kotlin/io/ksmt/ArithSimplifyTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ class ArithSimplifyTest : ExpressionSimplifyTest() {
5858
@Test
5959
fun testDiv() {
6060
testOperation(isInt = true, KContext::mkArithDiv, KContext::mkArithDivNoSimplify) {
61-
listOf(mkIntNum(0), mkIntNum(1), mkIntNum(-1)).uncheckedCast()
61+
listOf(
62+
mkIntNum(0), mkIntNum(1), mkIntNum(-1),
63+
// Values with non-trivial rounding
64+
mkIntNum(47), mkIntNum(-47), mkIntNum(13), mkIntNum(-13)
65+
).uncheckedCast()
6266
}
6367

6468
testOperation(isInt = false, KContext::mkArithDiv, KContext::mkArithDivNoSimplify) {

ksmt-cvc5/src/main/kotlin/io/ksmt/solver/cvc5/KCvc5ExprInternalizer.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,17 @@ class KCvc5ExprInternalizer(
10251025
}
10261026

10271027
override fun <T : KArithSort> transform(expr: KDivArithExpr<T>) = with(expr) {
1028-
transform(lhs, rhs) { lhs: Term, rhs: Term -> nsolver.mkTerm(Kind.DIVISION, lhs, rhs) }
1028+
transform(lhs, rhs) { lhs: Term, rhs: Term ->
1029+
arithDivide(sort, lhs, rhs)
1030+
}
1031+
}
1032+
1033+
private fun arithDivide(sort: KArithSort, lhs: Term, rhs: Term): Term = with(sort.ctx) {
1034+
when (sort) {
1035+
realSort -> nsolver.mkTerm(Kind.DIVISION, lhs, rhs)
1036+
intSort -> nsolver.mkTerm(Kind.INTS_DIVISION, lhs, rhs)
1037+
else -> throw KSolverUnsupportedFeatureException("Arith sort $sort is unsupported")
1038+
}
10291039
}
10301040

10311041
override fun <T : KArithSort> transform(expr: KPowerArithExpr<T>) = with(expr) {

0 commit comments

Comments
 (0)