Skip to content

Commit b7053e9

Browse files
committed
perf: skip the arithmetic prover for non-arithmetic literals
When estimating quantifier instantiation cost, PredictCostProver calls HandleArith.provedByArith for every literal/axiom pair. For a non-arithmetic literal it allocated a cache key, took the cache lock and ran formatArithTerm only to return the literal unproved -- and such literals dominate (~98% of calls even on arithmetic proofs). Both entry points now bail on a cheap arithmetic-shape check (>=, <=, plus = for the single-argument variant), exactly the condition under which the full prover would have returned the literal unchanged. Behaviour-preserving; cuts refinement time by roughly a third. Created with AI tooling support
1 parent dcc937d commit b7053e9

1 file changed

Lines changed: 29 additions & 2 deletions

File tree

  • key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics

key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ public class HandleArith {
2828

2929
private HandleArith() {}
3030

31+
/** The operator of {@code t} after stripping leading negations. */
32+
private static Operator strippedOp(JTerm t) {
33+
Operator op = t.op();
34+
while (op == Junctor.NOT) {
35+
t = t.sub(0);
36+
op = t.op();
37+
}
38+
return op;
39+
}
40+
41+
/** Whether {@code t} (ignoring leading negations) is an integer {@code >=} or {@code <=}. */
42+
private static boolean isArithComparison(JTerm t, IntegerLDT ig) {
43+
final Operator op = strippedOp(t);
44+
return op == ig.getGreaterOrEquals() || op == ig.getLessOrEquals();
45+
}
46+
3147
/**
3248
* try to prove atom by using polynomial
3349
*
@@ -36,6 +52,12 @@ private HandleArith() {}
3652
* <code>problem</code> if it cann't be proved.
3753
*/
3854
public static JTerm provedByArith(JTerm problem, Services services) {
55+
final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT();
56+
if (!isArithComparison(problem, integerLDT) && strippedOp(problem) != Equality.EQUALS) {
57+
// neither an (in)equality nor an equality: formatArithTerm yields false and
58+
// provedArithEqual returns the problem unchanged -- bail before locking the cache.
59+
return problem;
60+
}
3961
final LRUCache<JTerm, JTerm> provedByArithCache =
4062
services.getCaches().getProvedByArithFstCache();
4163
JTerm result;
@@ -47,7 +69,6 @@ public static JTerm provedByArith(JTerm problem, Services services) {
4769
}
4870

4971
TermBuilder tb = services.getTermBuilder();
50-
IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT();
5172

5273
final JTerm trueT = tb.tt();
5374
final JTerm falseT = tb.ff();
@@ -127,6 +148,13 @@ private static JTerm provedArithEqual(JTerm problem, TermBuilder tb, Services se
127148
* @return trueT if true, falseT if false, and atom if can't be prove;
128149
*/
129150
public static JTerm provedByArith(JTerm problem, JTerm axiom, Services services) {
151+
final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT();
152+
if (!isArithComparison(problem, integerLDT) || !isArithComparison(axiom, integerLDT)) {
153+
// not an arithmetic implication: formatArithTerm would yield false for one side and
154+
// this method returns the unproved problem -- bail before allocating the key and
155+
// taking the cache lock.
156+
return problem;
157+
}
130158
final Pair<JTerm, JTerm> key = new Pair<>(problem, axiom);
131159
final LRUCache<Pair<JTerm, JTerm>, JTerm> provedByArithCache =
132160
services.getCaches().getProvedByArithSndCache();
@@ -139,7 +167,6 @@ public static JTerm provedByArith(JTerm problem, JTerm axiom, Services services)
139167
}
140168

141169
final TermBuilder tb = services.getTermBuilder();
142-
final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT();
143170
final ServiceCaches caches = services.getCaches();
144171

145172
final JTerm cd = formatArithTerm(problem, tb, integerLDT, caches);

0 commit comments

Comments
 (0)