|
1 | 1 | package io.ksmt.expr.rewrite.simplify |
2 | 2 |
|
3 | 3 | import io.ksmt.KContext |
4 | | -import io.ksmt.expr.KAddArithExpr |
5 | 4 | import io.ksmt.expr.KExpr |
6 | | -import io.ksmt.expr.KIntNumExpr |
7 | | -import io.ksmt.expr.KMulArithExpr |
8 | | -import io.ksmt.expr.KRealNumExpr |
9 | | -import io.ksmt.expr.KToRealIntExpr |
10 | | -import io.ksmt.expr.KUnaryMinusArithExpr |
11 | 5 | import io.ksmt.sort.KArithSort |
12 | 6 | import io.ksmt.sort.KBoolSort |
13 | 7 | import io.ksmt.sort.KIntSort |
14 | 8 | import io.ksmt.sort.KRealSort |
15 | | -import io.ksmt.utils.ArithUtils.RealValue |
16 | | -import io.ksmt.utils.ArithUtils.bigIntegerValue |
17 | | -import io.ksmt.utils.ArithUtils.compareTo |
18 | | -import io.ksmt.utils.ArithUtils.numericValue |
19 | | -import io.ksmt.utils.ArithUtils.toRealValue |
20 | | -import io.ksmt.utils.uncheckedCast |
21 | | -import java.math.BigInteger |
22 | | -import kotlin.math.absoluteValue |
23 | 9 |
|
24 | | -fun <T : KArithSort> KContext.simplifyArithUnaryMinus(arg: KExpr<T>): KExpr<T> { |
25 | | - if (arg is KIntNumExpr) { |
26 | | - return mkIntNum(-arg.bigIntegerValue).uncheckedCast() |
27 | | - } |
| 10 | +fun <T : KArithSort> KContext.simplifyArithUnaryMinus(arg: KExpr<T>): KExpr<T> = |
| 11 | + simplifyArithUnaryMinusLight(arg, ::mkArithUnaryMinusNoSimplify) |
28 | 12 |
|
29 | | - if (arg is KRealNumExpr) { |
30 | | - return mkRealNum( |
31 | | - mkIntNum(-arg.numerator.bigIntegerValue), |
32 | | - arg.denominator |
33 | | - ).uncheckedCast() |
34 | | - } |
35 | | - |
36 | | - if (arg is KUnaryMinusArithExpr<T>) { |
37 | | - return arg.arg |
38 | | - } |
39 | | - |
40 | | - return mkArithUnaryMinusNoSimplify(arg) |
41 | | -} |
42 | | - |
43 | | -fun <T : KArithSort> KContext.simplifyArithAdd(args: List<KExpr<T>>): KExpr<T> { |
44 | | - require(args.isNotEmpty()) { |
45 | | - "Arith add requires at least a single argument" |
46 | | - } |
47 | | - |
48 | | - val simplifiedArgs = ArrayList<KExpr<T>>(args.size) |
49 | | - var constantTerm = RealValue.zero |
50 | | - |
51 | | - for (arg in args) { |
52 | | - // flat one level |
53 | | - if (arg is KAddArithExpr<T>) { |
54 | | - for (flatArg in arg.args) { |
55 | | - constantTerm = addArithTerm(constantTerm, flatArg, simplifiedArgs) |
56 | | - } |
57 | | - } else { |
58 | | - constantTerm = addArithTerm(constantTerm, arg, simplifiedArgs) |
59 | | - } |
60 | | - } |
61 | | - |
62 | | - if (simplifiedArgs.isEmpty()) { |
63 | | - return numericValue(constantTerm, args.first().sort) |
64 | | - } |
65 | | - |
66 | | - if (!constantTerm.isZero()) { |
67 | | - // prefer constant to be the first argument |
68 | | - val firstArg = simplifiedArgs.first() |
69 | | - simplifiedArgs[0] = numericValue(constantTerm, firstArg.sort) |
70 | | - simplifiedArgs.add(firstArg) |
71 | | - } |
72 | | - |
73 | | - if (simplifiedArgs.size == 1) { |
74 | | - return simplifiedArgs.single() |
75 | | - } |
76 | | - |
77 | | - return mkArithAddNoSimplify(simplifiedArgs) |
78 | | -} |
| 13 | +fun <T : KArithSort> KContext.simplifyArithAdd(args: List<KExpr<T>>): KExpr<T> = |
| 14 | + simplifyArithAddLight(args, ::mkArithAddNoSimplify) |
79 | 15 |
|
80 | 16 | fun <T : KArithSort> KContext.simplifyArithSub(args: List<KExpr<T>>): KExpr<T> = |
81 | | - if (args.size == 1) { |
82 | | - args.single() |
83 | | - } else { |
84 | | - require(args.isNotEmpty()) { |
85 | | - "Arith sub requires at least a single argument" |
86 | | - } |
87 | | - |
88 | | - val simplifiedArgs = arrayListOf(args.first()) |
89 | | - for (arg in args.drop(1)) { |
90 | | - simplifiedArgs += simplifyArithUnaryMinus(arg) |
91 | | - } |
92 | | - simplifyArithAdd(simplifiedArgs) |
93 | | - } |
94 | | - |
95 | | -fun <T : KArithSort> KContext.simplifyArithMul(args: List<KExpr<T>>): KExpr<T> { |
96 | | - require(args.isNotEmpty()) { |
97 | | - "Arith mul requires at least a single argument" |
98 | | - } |
99 | | - |
100 | | - val simplifiedArgs = ArrayList<KExpr<T>>(args.size) |
101 | | - var constantTerm = RealValue.one |
102 | | - |
103 | | - for (arg in args) { |
104 | | - // flat one level |
105 | | - if (arg is KMulArithExpr<T>) { |
106 | | - for (flatArg in arg.args) { |
107 | | - constantTerm = mulArithTerm(constantTerm, flatArg, simplifiedArgs) |
108 | | - } |
109 | | - } else { |
110 | | - constantTerm = mulArithTerm(constantTerm, arg, simplifiedArgs) |
111 | | - } |
112 | | - } |
113 | | - |
114 | | - if (simplifiedArgs.isEmpty() || constantTerm.isZero()) { |
115 | | - return numericValue(constantTerm, args.first().sort) |
116 | | - } |
117 | | - |
118 | | - if (constantTerm != RealValue.one) { |
119 | | - // prefer constant to be the first argument |
120 | | - val firstArg = simplifiedArgs.first() |
121 | | - simplifiedArgs[0] = numericValue(constantTerm, firstArg.sort) |
122 | | - simplifiedArgs.add(firstArg) |
123 | | - } |
124 | | - |
125 | | - if (simplifiedArgs.size == 1) { |
126 | | - return simplifiedArgs.single() |
127 | | - } |
128 | | - |
129 | | - return mkArithMulNoSimplify(simplifiedArgs) |
130 | | -} |
131 | | - |
132 | | -fun <T : KArithSort> KContext.simplifyArithDiv(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<T> { |
133 | | - val rValue = rhs.toRealValue() |
134 | | - |
135 | | - if (rValue != null && !rValue.isZero()) { |
136 | | - if (rValue == RealValue.one) { |
137 | | - return lhs |
138 | | - } |
139 | | - |
140 | | - if (rValue == RealValue.minusOne) { |
141 | | - return simplifyArithUnaryMinus(lhs) |
142 | | - } |
143 | | - |
144 | | - if (lhs is KIntNumExpr) { |
145 | | - return mkIntNum(lhs.bigIntegerValue / rValue.numerator).uncheckedCast() |
146 | | - } |
147 | | - |
148 | | - if (lhs is KRealNumExpr) { |
149 | | - val value = lhs.toRealValue().div(rValue) |
150 | | - return numericValue(value, lhs.sort).uncheckedCast() |
151 | | - } |
152 | | - } |
153 | | - return mkArithDivNoSimplify(lhs, rhs) |
154 | | -} |
| 17 | + rewriteArithSub(args, KContext::simplifyArithAdd, KContext::simplifyArithUnaryMinus) |
155 | 18 |
|
156 | | -fun <T : KArithSort> KContext.simplifyArithPower(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<T> { |
157 | | - val lValue = lhs.toRealValue() |
158 | | - val rValue = rhs.toRealValue() |
| 19 | +fun <T : KArithSort> KContext.simplifyArithMul(args: List<KExpr<T>>): KExpr<T> = |
| 20 | + simplifyArithMulLight(args, ::mkArithMulNoSimplify) |
159 | 21 |
|
160 | | - if (lValue != null && rValue != null) { |
161 | | - tryEvalArithPower(lValue, rValue)?.let { return castRealValue(it, lhs.sort) } |
162 | | - } |
| 22 | +fun <T : KArithSort> KContext.simplifyArithDiv(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<T> = |
| 23 | + simplifyArithDivLight(lhs, rhs, KContext::simplifyArithUnaryMinus, ::mkArithDivNoSimplify) |
163 | 24 |
|
164 | | - if (lValue == RealValue.one) { |
165 | | - return lhs |
166 | | - } |
| 25 | +fun <T : KArithSort> KContext.simplifyArithPower(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<T> = |
| 26 | + simplifyArithPowerLight(lhs, rhs, ::mkArithPowerNoSimplify) |
167 | 27 |
|
168 | | - if (rValue == RealValue.one) { |
169 | | - return lhs |
170 | | - } |
| 28 | +fun <T : KArithSort> KContext.simplifyArithLe(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<KBoolSort> = |
| 29 | + simplifyArithLeLight(lhs, rhs, ::mkArithLeNoSimplify) |
171 | 30 |
|
172 | | - return mkArithPowerNoSimplify(lhs, rhs) |
173 | | -} |
174 | | - |
175 | | -private fun tryEvalArithPower(base: RealValue, power: RealValue): RealValue? = when { |
176 | | - base.isZero() && power.isZero() -> null |
177 | | - power.isZero() -> RealValue.one |
178 | | - base.isZero() -> RealValue.zero |
179 | | - base == RealValue.one -> RealValue.one |
180 | | - power == RealValue.one -> base |
181 | | - power == RealValue.minusOne -> base.inverse() |
182 | | - else -> power.smallIntValue()?.let { powerIntValue -> |
183 | | - if (powerIntValue >= 0) { |
184 | | - base.pow(powerIntValue) |
185 | | - } else { |
186 | | - base.inverse().pow(powerIntValue.absoluteValue) |
187 | | - } |
188 | | - } |
189 | | -} |
190 | | - |
191 | | -private fun <T : KArithSort> KContext.castRealValue(value: RealValue, sort: T): KExpr<T> = when (sort) { |
192 | | - realSort -> numericValue(value, sort) |
193 | | - intSort -> mkIntNum(value.numerator / value.denominator).uncheckedCast() |
194 | | - else -> error("Unexpected arith sort: $sort") |
195 | | -} |
196 | | - |
197 | | -fun <T : KArithSort> KContext.simplifyArithLe(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<KBoolSort> { |
198 | | - if (lhs is KIntNumExpr && rhs is KIntNumExpr) { |
199 | | - return (lhs <= rhs).expr |
200 | | - } |
201 | | - if (lhs is KRealNumExpr && rhs is KRealNumExpr) { |
202 | | - return (lhs.toRealValue() <= rhs.toRealValue()).expr |
203 | | - } |
204 | | - return mkArithLeNoSimplify(lhs, rhs) |
205 | | -} |
206 | | - |
207 | | -fun <T : KArithSort> KContext.simplifyArithLt(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<KBoolSort> { |
208 | | - if (lhs is KIntNumExpr && rhs is KIntNumExpr) { |
209 | | - return (lhs < rhs).expr |
210 | | - } |
211 | | - if (lhs is KRealNumExpr && rhs is KRealNumExpr) { |
212 | | - return (lhs.toRealValue() < rhs.toRealValue()).expr |
213 | | - } |
214 | | - return mkArithLtNoSimplify(lhs, rhs) |
215 | | -} |
| 31 | +fun <T : KArithSort> KContext.simplifyArithLt(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<KBoolSort> = |
| 32 | + simplifyArithLtLight(lhs, rhs, ::mkArithLtNoSimplify) |
216 | 33 |
|
217 | 34 | fun <T : KArithSort> KContext.simplifyArithGe(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<KBoolSort> = |
218 | | - simplifyArithLe(rhs, lhs) |
| 35 | + rewriteArithGe(lhs, rhs, KContext::simplifyArithLe) |
219 | 36 |
|
220 | 37 | fun <T : KArithSort> KContext.simplifyArithGt(lhs: KExpr<T>, rhs: KExpr<T>): KExpr<KBoolSort> = |
221 | | - simplifyArithLt(rhs, lhs) |
222 | | - |
223 | | - |
224 | | -fun KContext.simplifyIntMod(lhs: KExpr<KIntSort>, rhs: KExpr<KIntSort>): KExpr<KIntSort> { |
225 | | - if (rhs is KIntNumExpr) { |
226 | | - val rValue = rhs.bigIntegerValue |
227 | | - |
228 | | - if (rValue == BigInteger.ONE || rValue == -BigInteger.ONE) { |
229 | | - return mkIntNum(0) |
230 | | - } |
231 | | - |
232 | | - if (rValue != BigInteger.ZERO && lhs is KIntNumExpr) { |
233 | | - return mkIntNum(evalIntMod(lhs.bigIntegerValue, rValue)) |
234 | | - } |
235 | | - } |
236 | | - return mkIntModNoSimplify(lhs, rhs) |
237 | | -} |
238 | | - |
239 | | -/** |
240 | | - * Eval integer mod wrt Int theory rules. |
241 | | - * */ |
242 | | -private fun evalIntMod(a: BigInteger, b: BigInteger): BigInteger { |
243 | | - val remainder = a.rem(b) |
244 | | - if (remainder >= BigInteger.ZERO) return remainder |
245 | | - return if (b >= BigInteger.ZERO) remainder + b else remainder - b |
246 | | -} |
247 | | - |
248 | | -fun KContext.simplifyIntRem(lhs: KExpr<KIntSort>, rhs: KExpr<KIntSort>): KExpr<KIntSort> { |
249 | | - if (rhs is KIntNumExpr) { |
250 | | - val rValue = rhs.bigIntegerValue |
251 | | - |
252 | | - if (rValue == BigInteger.ONE || rValue == -BigInteger.ONE) { |
253 | | - return mkIntNum(0) |
254 | | - } |
255 | | - |
256 | | - if (rValue != BigInteger.ZERO && lhs is KIntNumExpr) { |
257 | | - return mkIntNum(evalIntRem(lhs.bigIntegerValue, rValue)) |
258 | | - } |
259 | | - } |
260 | | - return mkIntRemNoSimplify(lhs, rhs) |
261 | | -} |
262 | | - |
263 | | -/** |
264 | | - * Eval integer rem wrt Int theory rules. |
265 | | - * */ |
266 | | -private fun evalIntRem(a: BigInteger, b: BigInteger): BigInteger { |
267 | | - val mod = evalIntMod(a, b) |
268 | | - return if (b >= BigInteger.ZERO) mod else -mod |
269 | | -} |
270 | | - |
271 | | -fun KContext.simplifyIntToReal(arg: KExpr<KIntSort>): KExpr<KRealSort> { |
272 | | - if (arg is KIntNumExpr) { |
273 | | - return mkRealNum(arg) |
274 | | - } |
275 | | - return mkIntToRealNoSimplify(arg) |
276 | | -} |
277 | | - |
278 | | -fun KContext.simplifyRealIsInt(arg: KExpr<KRealSort>): KExpr<KBoolSort> { |
279 | | - if (arg is KRealNumExpr) { |
280 | | - return (arg.toRealValue().denominator == BigInteger.ONE).expr |
281 | | - } |
282 | | - |
283 | | - // (isInt (int2real x)) ==> true |
284 | | - if (arg is KToRealIntExpr) { |
285 | | - return trueExpr |
286 | | - } |
287 | | - |
288 | | - return mkRealIsIntNoSimplify(arg) |
289 | | -} |
290 | | - |
291 | | -fun KContext.simplifyRealToInt(arg: KExpr<KRealSort>): KExpr<KIntSort> { |
292 | | - if (arg is KRealNumExpr) { |
293 | | - val realValue = arg.toRealValue() |
294 | | - return mkIntNum(realValue.numerator / realValue.denominator) |
295 | | - } |
296 | | - |
297 | | - // (real2int (int2real x)) ==> x |
298 | | - if (arg is KToRealIntExpr) { |
299 | | - return arg.arg |
300 | | - } |
301 | | - |
302 | | - return mkRealToIntNoSimplify(arg) |
303 | | -} |
304 | | - |
305 | | - |
306 | | -private fun <T : KArithSort> addArithTerm(value: RealValue, term: KExpr<T>, terms: MutableList<KExpr<T>>): RealValue { |
307 | | - if (term is KIntNumExpr) { |
308 | | - return value.add(term.toRealValue()) |
309 | | - } |
| 38 | + rewriteArithGt(lhs, rhs, KContext::simplifyArithLt) |
310 | 39 |
|
311 | | - if (term is KRealNumExpr) { |
312 | | - return value.add(term.toRealValue()) |
313 | | - } |
| 40 | +fun KContext.simplifyIntMod(lhs: KExpr<KIntSort>, rhs: KExpr<KIntSort>): KExpr<KIntSort> = |
| 41 | + simplifyIntModLight(lhs, rhs, ::mkIntModNoSimplify) |
314 | 42 |
|
315 | | - terms += term |
316 | | - return value |
317 | | -} |
| 43 | +fun KContext.simplifyIntRem(lhs: KExpr<KIntSort>, rhs: KExpr<KIntSort>): KExpr<KIntSort> = |
| 44 | + simplifyIntRemLight(lhs, rhs, ::mkIntRemNoSimplify) |
318 | 45 |
|
319 | | -private fun <T : KArithSort> mulArithTerm(value: RealValue, term: KExpr<T>, terms: MutableList<KExpr<T>>): RealValue { |
320 | | - if (term is KIntNumExpr) { |
321 | | - return value.mul(term.toRealValue()) |
322 | | - } |
| 46 | +fun KContext.simplifyIntToReal(arg: KExpr<KIntSort>): KExpr<KRealSort> = |
| 47 | + simplifyIntToRealLight(arg, ::mkIntToRealNoSimplify) |
323 | 48 |
|
324 | | - if (term is KRealNumExpr) { |
325 | | - return value.mul(term.toRealValue()) |
326 | | - } |
| 49 | +fun KContext.simplifyRealIsInt(arg: KExpr<KRealSort>): KExpr<KBoolSort> = |
| 50 | + simplifyRealIsIntLight(arg, ::mkRealIsIntNoSimplify) |
327 | 51 |
|
328 | | - terms += term |
329 | | - return value |
330 | | -} |
| 52 | +fun KContext.simplifyRealToInt(arg: KExpr<KRealSort>): KExpr<KIntSort> = |
| 53 | + simplifyRealToIntLight(arg, ::mkRealToIntNoSimplify) |
331 | 54 |
|
332 | | -private fun <T : KArithSort> KExpr<T>.toRealValue(): RealValue? = when (this) { |
333 | | - is KIntNumExpr -> toRealValue() |
334 | | - is KRealNumExpr -> toRealValue() |
335 | | - else -> null |
336 | | -} |
0 commit comments