From 2f7858f2b768e8ba324c46bdbe91c47df9f82256 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 3 Jul 2025 11:51:07 +0200 Subject: [PATCH 01/62] Modularize Feature strategies --- .../key/strategy/AbstractFeatureStrategy.java | 14 + .../ilkd/key/strategy/IntegerStrategy.java | 950 ++++++++++++++++++ .../ilkd/key/strategy/JavaCardDLStrategy.java | 854 +--------------- .../strategy/JavaCardDLStrategyFactory.java | 2 +- .../key/strategy/ModularJavaDLStrategy.java | 66 ++ 5 files changed, 1032 insertions(+), 854 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java index 90e67da550..388e47a96d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; +import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.NamespaceSet; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; @@ -10,6 +11,7 @@ import de.uka.ilkd.key.strategy.feature.instantiator.ForEachCP; import de.uka.ilkd.key.strategy.feature.instantiator.OneOfCP; import de.uka.ilkd.key.strategy.feature.instantiator.SVInstantiationCP; +import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; import org.key_project.logic.Name; import org.key_project.logic.Namespace; @@ -26,6 +28,7 @@ import org.key_project.prover.strategy.costbased.feature.instantiator.BackTrackingManager; import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; import org.key_project.prover.strategy.costbased.termProjection.TermBuffer; +import org.key_project.prover.strategy.costbased.termfeature.TermFeature; import org.key_project.prover.strategy.costbased.termgenerator.TermGenerator; import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSLList; @@ -131,6 +134,17 @@ public void instantiateApp(RuleApp app, PosInOccurrence pio, } while (btManager.backtrack()); } + protected final Services getServices() { + return getProof().getServices(); + } + + protected final Feature isBelow(TermFeature t) { + final de.uka.ilkd.key.strategy.termProjection.TermBuffer superTerm = + new de.uka.ilkd.key.strategy.termProjection.TermBuffer(); + return not(sum(superTerm, SuperTermGenerator.upwards(any(), getServices()), + not(applyTF(superTerm, t)))); + } + protected abstract RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java new file mode 100644 index 0000000000..5ef6017895 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -0,0 +1,950 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.ldt.IntegerLDT; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.op.Equality; +import de.uka.ilkd.key.logic.op.Junctor; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.feature.*; +import de.uka.ilkd.key.strategy.termProjection.*; +import de.uka.ilkd.key.strategy.termgenerator.MultiplesModEquationsGenerator; +import de.uka.ilkd.key.strategy.termgenerator.RootsGenerator; +import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; + +import org.key_project.logic.Name; +import org.key_project.logic.PosInTerm; +import org.key_project.logic.Term; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.TopRuleAppCost; +import org.key_project.prover.strategy.costbased.feature.Feature; +import org.key_project.prover.strategy.costbased.feature.FocusInAntecFeature; +import org.key_project.prover.strategy.costbased.feature.SumFeature; +import org.key_project.prover.strategy.costbased.termfeature.TermFeature; +import org.key_project.prover.strategy.costbased.termgenerator.SequentFormulasGenerator; +import org.key_project.prover.strategy.costbased.termgenerator.SubtermGenerator; + +import org.jspecify.annotations.NonNull; + + +public class IntegerStrategy extends AbstractFeatureStrategy { + + + public static final Name NAME = new Name("Integer Strategy"); + + private final RuleSetDispatchFeature costComputationDispatcher; + private final ArithTermFeatures tf; + private static final int IN_EQ_SIMP_NON_LIN_COST = 1000; + private static final int POLY_DIVISION_COST = -2250; + protected final StrategyProperties strategyProperties; + private final FormulaTermFeatures ff; + private final RuleSetDispatchFeature approvalDispatcher; + private final RuleSetDispatchFeature instantiationDispatcher; + + + public IntegerStrategy(Proof proof, StrategyProperties strategyProperties) { + super(proof); + this.strategyProperties = (StrategyProperties) strategyProperties.clone(); + this.tf = new ArithTermFeatures(proof.getServices().getTypeConverter().getIntegerLDT()); + this.ff = new FormulaTermFeatures(this.tf); + costComputationDispatcher = setupCostComputationF(); + approvalDispatcher = setupApprovalDispatcher(); + instantiationDispatcher = setupInstantiationF(); + } + + private RuleSetDispatchFeature setupInstantiationF() { + enableInstantiate(); + + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + + + setupArithPrimaryCategories(d); + setupDefOpsPrimaryCategories(d); + + setupInstantiationWithoutRetry(d); + + setupInEqSimpInstantiation(d); + + disableInstantiate(); + return d; + } + + private RuleSetDispatchFeature setupApprovalDispatcher() { + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); + + if (arithNonLinInferences()) { + setupMultiplyInequations(d, inftyConst()); + } + // these taclets are not supposed to be applied with metavariable + // instantiations + // I'll keep it here for the moment as documentation, but comment it out + // as meta variables are no longer part of KeY 2.x + /* + * bindRuleSet ( d, "inEqSimp_pullOutGcd", isInstantiated ( "elimGcd" ) ); bindRuleSet ( d, + * "polySimp_pullOutGcd", isInstantiated ( "elimGcd" ) ); + * + * bindRuleSet ( d, "inEqSimp_nonNegSquares", isInstantiated ( "squareFac" ) ); bindRuleSet + * ( d, "inEqSimp_nonLin_divide", isInstantiated ( "divY" ) ); bindRuleSet ( d, + * "inEqSimp_nonLin_pos", isInstantiated ( "divY" ) ); bindRuleSet ( d, + * "inEqSimp_nonLin_neg", isInstantiated ( "divY" ) ); + * + * bindRuleSet ( d, "inEqSimp_signCases", isInstantiated ( "signCasesLeft" ) ); + */ + + setupNewSymApproval(d, numbers); + + + bindRuleSet(d, "defOps_div", NonDuplicateAppModPositionFeature.INSTANCE); + bindRuleSet(d, "defOps_jdiv", NonDuplicateAppModPositionFeature.INSTANCE); + + if (arithNonLinInferences()) { + setupInEqCaseDistinctionsApproval(d); + } + + return d; + } + + private RuleSetDispatchFeature setupCostComputationF() { + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); + + + setupArithPrimaryCategories(d); + setupPolySimp(d, numbers); + setupInEqSimp(d, numbers); + + setupDefOpsPrimaryCategories(d); + + // For taclets that need instantiation, but where the instantiation is + // deterministic and does not have to be repeated at a later point, we + // setup the same feature terms as in the instantiation method. The + // definitions in setupInstantiationWithoutRetry should + // give cost infinity to those incomplete rule applications that will + // never be instantiated (so that these applications can be removed from + // the queue and do not have to be considered again). + setupInstantiationWithoutRetry(d); + + return d; + } + + private boolean arithNonLinInferences() { + return StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + } + + protected boolean arithDefOps() { + return StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals( + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)) + || StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Handling of arithmetic + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private void setupArithPrimaryCategories(RuleSetDispatchFeature d) { + // Gaussian elimination + Euclidian algorithm for linear equations; + // Buchberger's algorithmus for handling polynomial equations over + // the integers + + bindRuleSet(d, "polySimp_expand", -4500); + bindRuleSet(d, "polySimp_directEquations", -3000); + bindRuleSet(d, "polySimp_pullOutGcd", -2250); + bindRuleSet(d, "polySimp_leftNonUnit", -2000); + bindRuleSet(d, "polySimp_saturate", 0); + + // Omega test for handling linear arithmetic and inequalities over the + // integers; cross-multiplication + case distinctions for nonlinear + // inequalities + + bindRuleSet(d, "inEqSimp_expand", -4400); + bindRuleSet(d, "inEqSimp_directInEquations", -2900); + bindRuleSet(d, "inEqSimp_propagation", -2400); + bindRuleSet(d, "inEqSimp_pullOutGcd", -2150); + bindRuleSet(d, "inEqSimp_saturate", -1900); + bindRuleSet(d, "inEqSimp_forNormalisation", -1100); + bindRuleSet(d, "inEqSimp_special_nonLin", -1400); + + if (arithNonLinInferences()) { + bindRuleSet(d, "inEqSimp_nonLin", IN_EQ_SIMP_NON_LIN_COST); + } else { + bindRuleSet(d, "inEqSimp_nonLin", inftyConst()); + } + // polynomial division, simplification of fractions and mods + bindRuleSet(d, "polyDivision", POLY_DIVISION_COST); + + } + + private void setupPolySimp(RuleSetDispatchFeature d, IntegerLDT numbers) { + + // category "expansion" (normalising polynomial terms) + + bindRuleSet(d, "polySimp_elimSubNeg", longConst(-120)); + + bindRuleSet(d, "polySimp_homo", + add(applyTF("homoRight", add(not(tf.zeroLiteral), tf.polynomial)), + or(applyTF("homoLeft", or(tf.addF, tf.negMonomial)), + not(monSmallerThan("homoRight", "homoLeft", numbers))), + longConst(-120))); + + bindRuleSet(d, "polySimp_pullOutFactor", add(applyTFNonStrict("pullOutLeft", tf.literal), + applyTFNonStrict("pullOutRight", tf.literal), longConst(-120))); + + bindRuleSet(d, "polySimp_elimOneLeft", -120); + + bindRuleSet(d, "polySimp_elimOneRight", -120); + + bindRuleSet(d, "polySimp_mulOrder", add(applyTF("commRight", tf.monomial), or( + applyTF("commLeft", tf.addF), + add(applyTF("commLeft", tf.atom), atomSmallerThan("commLeft", "commRight", numbers))), + longConst(-100))); + + bindRuleSet(d, "polySimp_mulAssoc", + SumFeature.createSum(applyTF("mulAssocMono0", tf.monomial), + applyTF("mulAssocMono1", tf.monomial), applyTF("mulAssocAtom", tf.atom), + longConst(-80))); + + bindRuleSet(d, "polySimp_addOrder", + SumFeature.createSum(applyTF("commLeft", tf.monomial), + applyTF("commRight", tf.polynomial), + monSmallerThan("commRight", "commLeft", numbers), longConst(-60))); + + bindRuleSet(d, "polySimp_addAssoc", + SumFeature.createSum(applyTF("addAssocPoly0", tf.polynomial), + applyTF("addAssocPoly1", tf.polynomial), applyTF("addAssocMono", tf.monomial), + longConst(-10))); + + bindRuleSet(d, "polySimp_dist", + SumFeature.createSum(applyTF("distSummand0", tf.polynomial), + applyTF("distSummand1", tf.polynomial), + ifZero(applyTF("distCoeff", tf.monomial), longConst(-15), + applyTF("distCoeff", tf.polynomial)), + applyTF("distSummand0", tf.polynomial), + + applyTF("distSummand1", tf.polynomial), longConst(-35))); + + // category "direct equations" + + bindRuleSet(d, "polySimp_balance", + SumFeature + .createSum(applyTF("sepResidue", tf.polynomial), + ifZero(isInstantiated("sepPosMono"), + add(applyTF("sepPosMono", tf.nonNegMonomial), + monSmallerThan("sepResidue", "sepPosMono", numbers))), + ifZero(isInstantiated("sepNegMono"), + add(applyTF("sepNegMono", tf.negMonomial), + monSmallerThan("sepResidue", "sepNegMono", numbers))), + longConst(-30))); + + bindRuleSet(d, "polySimp_normalise", add(applyTF("invertRight", tf.zeroLiteral), + applyTF("invertLeft", tf.negMonomial), longConst(-30))); + + // application of equations: some specialised rules that handle + // monomials and their coefficients properly + + final TermBuffer eqLeft = new TermBuffer(); + final TermBuffer focus = new TermBuffer(); + + final TermFeature atLeastTwoLCEquation = + opSub(Equality.EQUALS, opSub(tf.mul, tf.atom, tf.atLeastTwoLiteral), tf.intF); + + final Feature validEqApplication = add(not(eq(eqLeft, focus)), + // otherwise, the normal equation rules can and should + // be used + ifZero(applyTF(AssumptionProjection.create(0), atLeastTwoLCEquation), + add(FocusInAntecFeature.getInstance(), + applyTF(FocusFormulaProjection.INSTANCE, atLeastTwoLCEquation))), + ReducibleMonomialsFeature.createReducible(focus, eqLeft)); + + final Feature eqMonomialFeature = add(not(directlyBelowSymbolAtIndex(tf.mul, -1)), + ifZero(MatchedAssumesFeature.INSTANCE, let(focus, FocusProjection.create(0), + let(eqLeft, sub(AssumptionProjection.create(0), 0), validEqApplication)))); + + bindRuleSet(d, "polySimp_applyEq", add(eqMonomialFeature, longConst(1))); + + bindRuleSet(d, "polySimp_applyEqRigid", add(eqMonomialFeature, longConst(2))); + + // + bindRuleSet(d, "defOps_expandModulo", + add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(-600))); + + // category "saturate" + + bindRuleSet(d, "polySimp_critPair", + ifZero(MatchedAssumesFeature.INSTANCE, + add(monSmallerThan("cpLeft1", "cpLeft2", numbers), + not(TrivialMonomialLCRFeature.create(instOf("cpLeft1"), instOf("cpLeft2")))))); + } + + private void setupDivModDivision(RuleSetDispatchFeature d) { + + final TermBuffer denomLC = new TermBuffer(); + final TermBuffer numTerm = new TermBuffer(); + final TermBuffer divCoeff = new TermBuffer(); + + // exact polynomial division + + final Feature checkNumTerm = ifZero( + add(not(applyTF(numTerm, tf.addF)), + ReducibleMonomialsFeature.createReducible(numTerm, denomLC)), + add(instantiate("polyDivCoeff", ReduceMonomialsProjection.create(numTerm, denomLC)), + inftyConst())); + + final Feature isReduciblePoly = + sum(numTerm, SubtermGenerator.rightTraverse(instOf("divNum"), tf.addF), checkNumTerm); + + // polynomial division modulo equations of the antecedent + + final Feature checkCoeffE = ifZero(contains(divCoeff, FocusProjection.create(0)), + // do not apply if the result contains the original term + longConst(0), add(instantiate("polyDivCoeff", divCoeff), inftyConst())); + + final Feature isReduciblePolyE = + sum(numTerm, SubtermGenerator.rightTraverse(instOf("divNum"), tf.addF), + ifZero(applyTF(numTerm, tf.addF), longConst(0), sum(divCoeff, + MultiplesModEquationsGenerator.create(numTerm, denomLC), checkCoeffE))); + + bindRuleSet(d, "defOps_divModPullOut", + SumFeature.createSum( + not(add(applyTF("divNum", tf.literal), applyTF("divDenom", tf.literal))), + applyTF("divNum", tf.polynomial), applyTF("divDenom", tf.polynomial), + ifZero(applyTF("divDenom", tf.addF), + let(denomLC, sub(instOf("divDenom"), 1), not(isReduciblePoly)), + let(denomLC, instOf("divDenom"), ifZero(isReduciblePoly, + // no possible division has been found so far + add(NotInScopeOfModalityFeature.INSTANCE, ifZero(isReduciblePolyE, + // try again later + longConst(-POLY_DIVISION_COST)))))), + longConst(100))); + + } + + + // For taclets that need instantiation, but where the instantiation is + // deterministic and does not have to be repeated at a later point, we + // setup the same feature terms as in the instantiation method. The + // definitions in setupInstantiationWithoutRetry should + // give cost infinity to those incomplete rule applications that will + // never be instantiated (so that these applications can be removed from + // the queue and do not have to be considered again). + private void setupPolySimpInstantiationWithoutRetry(RuleSetDispatchFeature d) { + final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); + + // category "direct equations" + + setupPullOutGcd(d, "polySimp_pullOutGcd", false); + + // category "polynomial division" + + setupDivModDivision(d); + + // category "handling of equations with non-unit-coefficients on + // left-hand side" + + bindRuleSet(d, "polySimp_newSym", + ifZero(not(isInstantiated("newSymDef")), SumFeature.createSum( + applyTF("newSymLeft", tf.atom), applyTF("newSymLeftCoeff", tf.atLeastTwoLiteral), + applyTF("newSymRight", tf.polynomial), instantiate("newSymDef", + MonomialColumnOp.create(instOf("newSymLeftCoeff"), instOf("newSymRight")))))); + + final TermBuffer divisor = new TermBuffer(); + final TermBuffer dividend = new TermBuffer(); + + bindRuleSet(d, "polySimp_applyEqPseudo", + add(applyTF("aePseudoTargetLeft", tf.monomial), + applyTF("aePseudoTargetRight", tf.polynomial), + ifZero(MatchedAssumesFeature.INSTANCE, + SumFeature.createSum(DiffFindAndIfFeature.INSTANCE, + applyTF("aePseudoLeft", add(tf.nonCoeffMonomial, not(tf.atom))), + applyTF("aePseudoLeftCoeff", tf.atLeastTwoLiteral), + applyTF("aePseudoRight", tf.polynomial), + MonomialsSmallerThanFeature.create(instOf("aePseudoRight"), + instOf("aePseudoLeft"), numbers), + let(divisor, instOf("aePseudoLeft"), + let(dividend, instOf("aePseudoTargetLeft"), + add(ReducibleMonomialsFeature.createReducible(dividend, divisor), + instantiate("aePseudoTargetFactor", + ReduceMonomialsProjection.create(dividend, divisor))))))))); + } + + private void setupNewSymApproval(RuleSetDispatchFeature d, IntegerLDT numbers) { + final TermBuffer antecFor = new TermBuffer(); + final Feature columnOpEq = applyTF(antecFor, + opSub(tf.eq, opSub(tf.mul, tf.atom, tf.atLeastTwoLiteral), tf.polynomial)); + final Feature biggerLeftSide = + MonomialsSmallerThanFeature.create(instOf("newSymLeft"), + subAt(antecFor, PosInTerm.getTopLevel().down(0).down(0)), numbers); + bindRuleSet(d, "polySimp_newSym", add(isInstantiated("newSymDef"), sum(antecFor, + SequentFormulasGenerator.antecedent(), not(add(columnOpEq, biggerLeftSide))))); + } + + private void setupPullOutGcd(RuleSetDispatchFeature d, String ruleSet, boolean roundingUp) { + final TermBuffer gcd = new TermBuffer(); + + final Feature instantiateDivs; + if (roundingUp) { + instantiateDivs = add( + instantiate("elimGcdLeftDiv", + DividePolynomialsProjection.createRoundingUp(gcd, instOf("elimGcdLeft"))), + instantiate("elimGcdRightDiv", + DividePolynomialsProjection.createRoundingUp(gcd, instOf("elimGcdRight")))); + } else { + instantiateDivs = add( + instantiate("elimGcdLeftDiv", + DividePolynomialsProjection.createRoundingDown(gcd, instOf("elimGcdLeft"))), + instantiate("elimGcdRightDiv", + DividePolynomialsProjection.createRoundingDown(gcd, instOf("elimGcdRight")))); + } + bindRuleSet(d, ruleSet, + add(applyTF("elimGcdLeft", tf.nonNegMonomial), applyTF("elimGcdRight", tf.polynomial), + let(gcd, CoeffGcdProjection.create(instOf("elimGcdLeft"), instOf("elimGcdRight")), + add(applyTF(gcd, tf.atLeastTwoLiteral), instantiate("elimGcd", gcd), + instantiateDivs)))); + } + + private void setupInEqSimp(RuleSetDispatchFeature d, IntegerLDT numbers) { + + // category "expansion" (normalising inequations) + + bindRuleSet(d, "inEqSimp_moveLeft", -90); + + bindRuleSet(d, "inEqSimp_makeNonStrict", -80); + + bindRuleSet(d, "inEqSimp_commute", + SumFeature.createSum(applyTF("commRight", tf.monomial), + applyTF("commLeft", tf.polynomial), + monSmallerThan("commLeft", "commRight", numbers), longConst(-40))); + + // this is copied from "polySimp_homo" + bindRuleSet(d, "inEqSimp_homo", + add(applyTF("homoRight", add(not(tf.zeroLiteral), tf.polynomial)), + or(applyTF("homoLeft", or(tf.addF, tf.negMonomial)), + not(monSmallerThan("homoRight", "homoLeft", numbers))))); + + // category "direct inequations" + + // this is copied from "polySimp_balance" + bindRuleSet(d, "inEqSimp_balance", + add(applyTF("sepResidue", tf.polynomial), + ifZero(isInstantiated("sepPosMono"), + add(applyTF("sepPosMono", tf.nonNegMonomial), + monSmallerThan("sepResidue", "sepPosMono", numbers))), + ifZero(isInstantiated("sepNegMono"), add(applyTF("sepNegMono", tf.negMonomial), + monSmallerThan("sepResidue", "sepNegMono", numbers))))); + + // this is copied from "polySimp_normalise" + bindRuleSet(d, "inEqSimp_normalise", + add(applyTF("invertRight", tf.zeroLiteral), applyTF("invertLeft", tf.negMonomial))); + + // category "saturate" + + bindRuleSet(d, "inEqSimp_antiSymm", longConst(-20)); + + bindRuleSet(d, "inEqSimp_exactShadow", + SumFeature.createSum(applyTF("esLeft", tf.nonCoeffMonomial), + applyTFNonStrict("esCoeff2", tf.nonNegLiteral), applyTF("esRight2", tf.polynomial), + ifZero(MatchedAssumesFeature.INSTANCE, + SumFeature.createSum(applyTFNonStrict("esCoeff1", tf.nonNegLiteral), + applyTF("esRight1", tf.polynomial), + not(PolynomialValuesCmpFeature.leq(instOf("esRight2"), instOf("esRight1"), + instOfNonStrict("esCoeff1"), instOfNonStrict("esCoeff2"))))))); + + // category "propagation" + + bindRuleSet(d, "inEqSimp_contradInEqs", + add(applyTF("contradLeft", tf.monomial), + ifZero(MatchedAssumesFeature.INSTANCE, + SumFeature.createSum(DiffFindAndIfFeature.INSTANCE, + applyTF("contradRightSmaller", tf.polynomial), + applyTF("contradRightBigger", tf.polynomial), + applyTFNonStrict("contradCoeffSmaller", tf.posLiteral), + applyTFNonStrict("contradCoeffBigger", tf.posLiteral), + PolynomialValuesCmpFeature.lt(instOf("contradRightSmaller"), + instOf("contradRightBigger"), instOfNonStrict("contradCoeffBigger"), + instOfNonStrict("contradCoeffSmaller")))))); + + bindRuleSet(d, "inEqSimp_contradEqs", + add(applyTF("contradLeft", tf.monomial), + ifZero(MatchedAssumesFeature.INSTANCE, + SumFeature.createSum(applyTF("contradRightSmaller", tf.polynomial), + applyTF("contradRightBigger", tf.polynomial), PolynomialValuesCmpFeature + .lt(instOf("contradRightSmaller"), instOf("contradRightBigger")))), + longConst(-60))); + + bindRuleSet(d, "inEqSimp_strengthen", longConst(-30)); + + bindRuleSet(d, "inEqSimp_subsumption", + add(applyTF("subsumLeft", tf.monomial), + ifZero(MatchedAssumesFeature.INSTANCE, + SumFeature.createSum(DiffFindAndIfFeature.INSTANCE, + applyTF("subsumRightSmaller", tf.polynomial), + applyTF("subsumRightBigger", tf.polynomial), + applyTFNonStrict("subsumCoeffSmaller", tf.posLiteral), + applyTFNonStrict("subsumCoeffBigger", tf.posLiteral), + PolynomialValuesCmpFeature.leq(instOf("subsumRightSmaller"), + instOf("subsumRightBigger"), instOfNonStrict("subsumCoeffBigger"), + instOfNonStrict("subsumCoeffSmaller")))))); + + // category "handling of non-linear inequations" + + if (arithNonLinInferences()) { + setupMultiplyInequations(d, longConst(100)); + + bindRuleSet(d, "inEqSimp_split_eq", add(TopLevelFindFeature.SUCC, longConst(-100))); + + bindRuleSet(d, "inEqSimp_signCases", not(isInstantiated("signCasesLeft"))); + } + + // category "normalisation of formulas" + // (e.g., quantified formulas, where the normal sequent calculus + // does not do any normalisation) + + bindRuleSet(d, "inEqSimp_and_contradInEqs", + SumFeature.createSum(applyTF("contradLeft", tf.monomial), + applyTF("contradRightSmaller", tf.polynomial), + applyTF("contradRightBigger", tf.polynomial), PolynomialValuesCmpFeature + .lt(instOf("contradRightSmaller"), instOf("contradRightBigger")))); + + bindRuleSet(d, "inEqSimp_andOr_subsumption", + SumFeature.createSum(applyTF("subsumLeft", tf.monomial), + applyTF("subsumRightSmaller", tf.polynomial), + applyTF("subsumRightBigger", tf.polynomial), PolynomialValuesCmpFeature + .leq(instOf("subsumRightSmaller"), instOf("subsumRightBigger")))); + + bindRuleSet(d, "inEqSimp_and_subsumptionEq", + SumFeature.createSum(applyTF("subsumLeft", tf.monomial), + applyTF("subsumRightSmaller", tf.polynomial), + applyTF("subsumRightBigger", tf.polynomial), PolynomialValuesCmpFeature + .lt(instOf("subsumRightSmaller"), instOf("subsumRightBigger")))); + + final Term tOne = getServices().getTermBuilder().zTerm("1"); + final TermBuffer one = new TermBuffer() { + @Override + public void setContent(Term term, MutableState mState) {} + + @Override + public @NonNull Term getContent(MutableState mState) { + return tOne; + } + + @Override + public @NonNull Term toTerm(RuleApp app, PosInOccurrence pos, + Goal goal, MutableState mState) { + return tOne; + } + }; + + final JTerm tTwo = getServices().getTermBuilder().zTerm("2"); + final TermBuffer two = new TermBuffer() { + @Override + public void setContent(Term term, MutableState mState) {} + + @Override + public @NonNull Term getContent(MutableState mState) { + return tTwo; + } + + @Override + public @NonNull Term toTerm(RuleApp app, PosInOccurrence pos, + Goal goal, MutableState mState) { + return tTwo; + } + }; + + bindRuleSet(d, "inEqSimp_or_tautInEqs", + SumFeature.createSum(applyTF("tautLeft", tf.monomial), + applyTF("tautRightSmaller", tf.polynomial), + applyTF("tautRightBigger", tf.polynomial), + PolynomialValuesCmpFeature.leq(instOf("tautRightSmaller"), + opTerm(numbers.getAdd(), one, instOf("tautRightBigger"))))); + + bindRuleSet(d, "inEqSimp_or_weaken", + SumFeature.createSum(applyTF("weakenLeft", tf.monomial), + applyTF("weakenRightSmaller", tf.polynomial), + applyTF("weakenRightBigger", tf.polynomial), + PolynomialValuesCmpFeature.eq( + opTerm(numbers.getAdd(), one, instOf("weakenRightSmaller")), + instOf("weakenRightBigger")))); + + bindRuleSet(d, "inEqSimp_or_antiSymm", + SumFeature.createSum(applyTF("antiSymmLeft", tf.monomial), + applyTF("antiSymmRightSmaller", tf.polynomial), + applyTF("antiSymmRightBigger", tf.polynomial), + PolynomialValuesCmpFeature.eq( + opTerm(numbers.getAdd(), two, instOf("antiSymmRightSmaller")), + instOf("antiSymmRightBigger")))); + + } + + private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature notAllowedF) { + final TermBuffer intRel = new TermBuffer(); + + /* + * final Feature partiallyBounded = not ( sum ( intRel, SequentFormulasGenerator.sequent (), + * not ( add ( applyTF ( intRel, tf.intRelation ), InEquationMultFeature .partiallyBounded ( + * instOf ( "multLeft" ), instOf ( "multFacLeft" ), sub ( intRel, 0 ) ) ) ) ) ); + */ + + final Feature totallyBounded = not(sum(intRel, SequentFormulasGenerator.sequent(), + not(add(applyTF(intRel, tf.intRelation), InEquationMultFeature + .totallyBounded(instOf("multLeft"), instOf("multFacLeft"), sub(intRel, 0)))))); + + final Feature exactlyBounded = not(sum(intRel, SequentFormulasGenerator.sequent(), + not(add(applyTF(intRel, tf.intRelation), InEquationMultFeature + .exactlyBounded(instOf("multLeft"), instOf("multFacLeft"), sub(intRel, 0)))))); + + // this is a bit hackish + // + // really, one would need a possibility to express that the cost + // computation for the rule application should be post-poned (and + // repeated at a later point) if the product of the left sides does not + // have any similarity with existing left sides + // (AllowInEquationMultiplication returns false). We + // simulate this by returning non-infinite costs here, but by declining + // the rule application in isApprovedApp). This is not + // perfect, because it is not possible to distinguish between the + // re-cost-computation delay and the normal costs for a rule application + bindRuleSet(d, "inEqSimp_nonLin_multiply", add(applyTF("multLeft", tf.nonNegMonomial), + applyTF("multRight", tf.polynomial), + ifZero(MatchedAssumesFeature.INSTANCE, + SumFeature.createSum(applyTF("multFacLeft", tf.nonNegMonomial), + ifZero(applyTF("multRight", tf.literal), longConst(-100)), + ifZero(applyTF("multFacRight", tf.literal), longConst(-100), + applyTF("multFacRight", tf.polynomial)), + /* + * ifZero ( applyTF ( "multRight", tf.literal ), longConst ( -100 ), applyTF ( + * "multRight", tf.polynomial ) ), ifZero ( applyTF ( "multFacRight", tf.literal + * ), longConst ( -100 ), applyTF ( "multFacRight", tf.polynomial ) ), + */ + not(TermSmallerThanFeature.create(FocusProjection.create(0), + AssumptionProjection.create(0))), + ifZero(exactlyBounded, longConst(0), + ifZero(totallyBounded, longConst(100), notAllowedF)) + /* + * ifZero ( partiallyBounded, longConst ( 400 ), notAllowedF ) ) ), + */ + /* + * applyTF ( "multLeft", rec ( tf.mulF, longTermConst ( 20 ) ) ), applyTF ( + * "multFacLeft", rec ( tf.mulF, longTermConst ( 20 ) ) ), applyTF ( "multRight", + * rec ( tf.addF, longTermConst ( 4 ) ) ), applyTF ( "multFacRight", rec ( tf.addF, + * longTermConst ( 4 ) ) ), + */ + ), notAllowedF))); + } + + private void setupInEqSimpInstantiation(RuleSetDispatchFeature d) { + // category "handling of non-linear inequations" + + setupSquaresAreNonNegative(d); + + if (arithNonLinInferences()) { + setupInEqCaseDistinctions(d); + } + } + + // For taclets that need instantiation, but where the instantiation is + // deterministic and does not have to be repeated at a later point, we + // setup the same feature terms as in the instantiation method. The + // definitions in setupInstantiationWithoutRetry should + // give cost infinity to those incomplete rule applications that will + // never be instantiated (so that these applications can be removed from + // the queue and do not have to be considered again). + private void setupInEqSimpInstantiationWithoutRetry(RuleSetDispatchFeature d) { + // category "direct inequations" + + setupPullOutGcd(d, "inEqSimp_pullOutGcd_leq", false); + setupPullOutGcd(d, "inEqSimp_pullOutGcd_geq", true); + + // more efficient (but not confluent) versions for the antecedent + bindRuleSet(d, "inEqSimp_pullOutGcd_antec", -10); + + // category "handling of non-linear inequations" + + final TermBuffer divisor = new TermBuffer(); + final TermBuffer dividend = new TermBuffer(); + + bindRuleSet(d, "inEqSimp_nonLin_divide", SumFeature.createSum( + applyTF("divProd", tf.nonCoeffMonomial), + applyTFNonStrict("divProdBoundNonPos", tf.nonPosLiteral), + applyTFNonStrict("divProdBoundNonNeg", tf.nonNegLiteral), + ifZero(MatchedAssumesFeature.INSTANCE, + let(divisor, instOf("divX"), let(dividend, instOf("divProd"), + SumFeature.createSum(applyTF(divisor, tf.nonCoeffMonomial), + not(eq(dividend, divisor)), applyTFNonStrict("divXBoundPos", tf.posLiteral), + applyTFNonStrict("divXBoundNeg", tf.negLiteral), + ReducibleMonomialsFeature.createReducible(dividend, divisor), instantiate( + "divY", ReduceMonomialsProjection.create(dividend, divisor)))))))); + + setupNonLinTermIsPosNeg(d, "inEqSimp_nonLin_pos", true); + setupNonLinTermIsPosNeg(d, "inEqSimp_nonLin_neg", false); + } + + private void setupNonLinTermIsPosNeg(RuleSetDispatchFeature d, String ruleSet, boolean pos) { + final TermBuffer divisor = new TermBuffer(); + final TermBuffer dividend = new TermBuffer(); + final TermBuffer quotient = new TermBuffer(); + final TermBuffer antecFor = new TermBuffer(); + + bindRuleSet(d, ruleSet, + SumFeature + .createSum(applyTF("divProd", tf.nonCoeffMonomial), + applyTFNonStrict("divProdBoundPos", tf.posLiteral), + applyTFNonStrict("divProdBoundNeg", tf.negLiteral), + ifZero(MatchedAssumesFeature.INSTANCE, + let(divisor, instOf("divX"), let(dividend, instOf("divProd"), + SumFeature.createSum(applyTF(divisor, tf.nonCoeffMonomial), + not(applyTF(dividend, eq(divisor))), + applyTFNonStrict("divXBoundNonPos", tf.nonPosLiteral), + applyTFNonStrict("divXBoundNonNeg", tf.nonNegLiteral), + ReducibleMonomialsFeature.createReducible(dividend, divisor), + let(quotient, + ReduceMonomialsProjection.create(dividend, divisor), add( + sum(antecFor, SequentFormulasGenerator.antecedent(), + not(applyTF(antecFor, + pos ? opSub(tf.geq, eq(quotient), tf.posLiteral) + : opSub(tf.leq, eq(quotient), + tf.negLiteral)))), + instantiate("divY", quotient))))))))); + } + + private void setupSquaresAreNonNegative(RuleSetDispatchFeature d) { + final TermBuffer intRel = new TermBuffer(); + final TermBuffer product = new TermBuffer(); + final TermBuffer factor = new TermBuffer(); + + final Feature productContainsSquare = + applyTF(sub(product, 0), or(eq(factor), opSub(tf.mul, any(), eq(factor)))); + final Feature productIsProduct = applyTF(product, opSub(tf.mul, any(), not(tf.mulF))); + + bindRuleSet(d, "inEqSimp_nonNegSquares", + forEach(intRel, SequentFormulasGenerator.sequent(), + ifZero(applyTF(intRel, tf.intRelation), + forEach(product, SubtermGenerator.leftTraverse(sub(intRel, 0), tf.mulF), + ifZero(productIsProduct, let(factor, sub(product, 1), + ifZero(productContainsSquare, instantiate("squareFac", factor)))))))); + } + + private void setupInEqCaseDistinctions(RuleSetDispatchFeature d) { + final TermBuffer intRel = new TermBuffer(); + final TermBuffer atom = new TermBuffer(); + final TermBuffer rootInf = new TermBuffer(); + + final Feature posNegSplitting = forEach(intRel, SequentFormulasGenerator.antecedent(), + add(applyTF(intRel, tf.intRelation), + forEach(atom, SubtermGenerator.leftTraverse(sub(intRel, 0), tf.mulF), + SumFeature.createSum(applyTF(atom, add(tf.atom, not(tf.literal))), + allowPosNegCaseDistinction(atom), instantiate("signCasesLeft", atom), + longConst(IN_EQ_SIMP_NON_LIN_COST + 200) + // , + // applyTF ( atom, rec ( any (), + // longTermConst ( 5 ) ) ) + )))); + + bindRuleSet(d, "inEqSimp_signCases", posNegSplitting); + + final Feature strengthening = forEach(intRel, SequentFormulasGenerator.antecedent(), + SumFeature.createSum( + applyTF(intRel, add(or(tf.geqF, tf.leqF), sub(tf.atom, tf.literal))), + instantiate("cutFormula", opTerm(tf.eq, sub(intRel, 0), sub(intRel, 1))), + longConst(IN_EQ_SIMP_NON_LIN_COST + 300) + // , + // applyTF ( sub ( intRel, 0 ), + // rec ( any (), longTermConst ( 5 ) ) ) + )); + + final Feature rootInferences = forEach(intRel, SequentFormulasGenerator.antecedent(), + add(isRootInferenceProducer(intRel), + forEach(rootInf, RootsGenerator.create(intRel, getServices()), + add(instantiate("cutFormula", rootInf), + ifZero(applyTF(rootInf, op(Junctor.OR)), longConst(50)), + ifZero(applyTF(rootInf, op(Junctor.AND)), longConst(20)))), + longConst(IN_EQ_SIMP_NON_LIN_COST))); + + // noinspection unchecked + bindRuleSet(d, "cut", oneOf(new Feature[] { strengthening, rootInferences })); + } + + private Feature isRootInferenceProducer(TermBuffer intRel) { + return applyTF(intRel, add(tf.intRelation, sub(tf.nonCoeffMonomial, tf.literal))); + } + + private Feature allowPosNegCaseDistinction(TermBuffer atom) { + final TermBuffer antecFor = new TermBuffer(); + final TermFeature eqAtom = eq(atom); + + return add(not(succIntEquationExists()), + sum(antecFor, SequentFormulasGenerator.antecedent(), + not(applyTF(antecFor, or(opSub(tf.eq, eqAtom, any()), + opSub(tf.leq, eqAtom, tf.negLiteral), opSub(tf.geq, eqAtom, tf.posLiteral)))))); + } + + private Feature allowInEqStrengthening(TermBuffer atom, TermBuffer literal) { + final TermBuffer antecFor = new TermBuffer(); + + return add(not(succIntEquationExists()), + not(sum(antecFor, SequentFormulasGenerator.antecedent(), + not(applyTF(antecFor, add(or(tf.leqF, tf.geqF), sub(eq(atom), eq(literal)))))))); + } + + private Feature succIntEquationExists() { + final TermBuffer succFor = new TermBuffer(); + + return not(sum(succFor, SequentFormulasGenerator.succedent(), + not(applyTF(succFor, tf.intEquation)))); + } + + private void setupInEqCaseDistinctionsApproval(RuleSetDispatchFeature d) { + final TermBuffer atom = new TermBuffer(); + final TermBuffer literal = new TermBuffer(); + final TermBuffer intRel = new TermBuffer(); + final TermBuffer rootInf = new TermBuffer(); + + bindRuleSet(d, "inEqSimp_signCases", add(isInstantiated("signCasesLeft"), + let(atom, instOf("signCasesLeft"), allowPosNegCaseDistinction(atom)))); + + // this is somewhat ugly. we should introduce some concept of "tagging" + // rule application so that they can be recognised again later + bindRuleSet(d, "cut", + add(isInstantiated("cutFormula"), or( + not(sum(intRel, SequentFormulasGenerator.antecedent(), + ifZero(isRootInferenceProducer(intRel), + sum(rootInf, RootsGenerator.create(intRel, getServices()), + not(eq(instOf("cutFormula"), rootInf)))))), + ifZero(applyTF("cutFormula", opSub(tf.eq, tf.atom, tf.literal)), + let(atom, sub(instOf("cutFormula"), 0), let(literal, + sub(instOf("cutFormula"), 1), allowInEqStrengthening(atom, literal))))))); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Axiomatisation and algorithms for further arithmetic operations: + // division, modulus, modular Java operations + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private void setupDefOpsPrimaryCategories(RuleSetDispatchFeature d) { + + if (arithDefOps()) { + // the axiom defining division only has to be inserted once, because + // it adds equations to the antecedent + bindRuleSet(d, "defOps_div", + SumFeature.createSum(NonDuplicateAppModPositionFeature.INSTANCE, + applyTF("divNum", tf.polynomial), applyTF("divDenom", tf.polynomial), + applyTF("divNum", tf.notContainsDivMod), + applyTF("divDenom", tf.notContainsDivMod), + ifZero(isBelow(ff.modalOperator), longConst(200)))); + + bindRuleSet(d, "defOps_jdiv", + SumFeature.createSum(NonDuplicateAppModPositionFeature.INSTANCE, + applyTF("divNum", tf.polynomial), applyTF("divDenom", tf.polynomial), + applyTF("divNum", tf.notContainsDivMod), + applyTF("divDenom", tf.notContainsDivMod), + ifZero(isBelow(ff.modalOperator), longConst(200)))); + + bindRuleSet(d, "defOps_jdiv_inline", add(applyTF("divNum", tf.literal), + applyTF("divDenom", tf.polynomial), longConst(-5000))); + + setupDefOpsExpandMod(d); + + bindRuleSet(d, "defOps_expandRanges", -8000); + bindRuleSet(d, "defOps_expandJNumericOp", -500); + bindRuleSet(d, "defOps_modHomoEq", -5000); + } else { + bindRuleSet(d, "defOps_div", inftyConst()); + bindRuleSet(d, "defOps_jdiv", inftyConst()); + + bindRuleSet(d, "defOps_jdiv_inline", add(applyTF("divNum", tf.literal), + applyTF("divDenom", tf.literal), longConst(-4000))); + + bindRuleSet(d, "defOps_mod", add(applyTF("divNum", tf.literal), + applyTF("divDenom", tf.literal), longConst(-4000))); + + bindRuleSet(d, "defOps_expandRanges", inftyConst()); + bindRuleSet(d, "defOps_expandJNumericOp", inftyConst()); + bindRuleSet(d, "defOps_modHomoEq", inftyConst()); + } + + } + + private void setupDefOpsExpandMod(RuleSetDispatchFeature d) { + final TermBuffer superTerm = new TermBuffer(); + + final Feature subsumedModulus = + add(applyTF(superTerm, sub(opSub(tf.mod, any(), tf.literal), tf.zeroLiteral)), + PolynomialValuesCmpFeature.divides(instOf("divDenom"), sub(sub(superTerm, 0), 1))); + + final Feature exSubsumedModulus = add(applyTF("divDenom", tf.literal), + not(sum(superTerm, + SuperTermGenerator.upwardsWithIndex(sub(or(tf.addF, tf.mulF), any()), + getServices()), + not(subsumedModulus)))); + + bindRuleSet(d, "defOps_mod", + ifZero(add(applyTF("divNum", tf.literal), applyTF("divDenom", tf.literal)), + longConst(-4000), + SumFeature.createSum(applyTF("divNum", tf.polynomial), + applyTF("divDenom", tf.polynomial), + ifZero(isBelow(ff.modalOperator), exSubsumedModulus, + or(add(applyTF("divNum", tf.notContainsDivMod), + applyTF("divDenom", tf.notContainsDivMod)), exSubsumedModulus)), + longConst(-3500)))); + } + + /** + * For taclets that need instantiation, but where the instantiation is deterministic and does + * not have to be repeated at a later point, we setup the same feature terms both in the cost + * computation method and in the instantiation method. The definitions in + * setupInstantiationWithoutRetry should give cost infinity to those incomplete + * rule applications that will never be instantiated (so that these applications can be removed + * from the queue and do not have to be considered again). + */ + private void setupInstantiationWithoutRetry(RuleSetDispatchFeature d) { + setupPolySimpInstantiationWithoutRetry(d); + setupInEqSimpInstantiationWithoutRetry(d); + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) + .equals(StrategyProperties.STOPMODE_NONCLOSE); + } + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return !(approvalDispatcher.computeCost(app, pio, goal, + new MutableState()) == TopRuleAppCost.INSTANCE); + + } + + @Override + protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return instantiationDispatcher.computeCost(app, pio, goal, mState); + } + + @Override + public Name name() { + return NAME; + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, Goal goal, MutableState mState) { + return this.costComputationDispatcher.computeCost(app, pos, goal, mState); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 5b18237454..223f02aa14 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -5,14 +5,12 @@ import java.util.concurrent.atomic.AtomicLong; -import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.ldt.BooleanLDT; import de.uka.ilkd.key.ldt.CharListLDT; import de.uka.ilkd.key.ldt.HeapLDT; import de.uka.ilkd.key.ldt.IntegerLDT; import de.uka.ilkd.key.ldt.LocSetLDT; import de.uka.ilkd.key.ldt.SeqLDT; -import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.op.Equality; import de.uka.ilkd.key.logic.op.Junctor; import de.uka.ilkd.key.logic.op.Quantifier; @@ -32,15 +30,11 @@ import de.uka.ilkd.key.strategy.termfeature.*; import de.uka.ilkd.key.strategy.termgenerator.AllowedCutPositionsGenerator; import de.uka.ilkd.key.strategy.termgenerator.HeapGenerator; -import de.uka.ilkd.key.strategy.termgenerator.MultiplesModEquationsGenerator; -import de.uka.ilkd.key.strategy.termgenerator.RootsGenerator; import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; import de.uka.ilkd.key.strategy.termgenerator.TriggeredInstantiations; import de.uka.ilkd.key.util.MiscTools; import org.key_project.logic.Name; -import org.key_project.logic.PosInTerm; -import org.key_project.logic.Term; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.proof.rulefilter.SetRuleFilter; import org.key_project.prover.rules.RuleApp; @@ -54,8 +48,6 @@ import org.key_project.prover.strategy.costbased.termfeature.IsNonRigidTermFeature; import org.key_project.prover.strategy.costbased.termfeature.OperatorClassTF; import org.key_project.prover.strategy.costbased.termfeature.TermFeature; -import org.key_project.prover.strategy.costbased.termgenerator.SequentFormulasGenerator; -import org.key_project.prover.strategy.costbased.termgenerator.SubtermGenerator; import org.jspecify.annotations.NonNull; @@ -69,9 +61,6 @@ public class JavaCardDLStrategy extends AbstractFeatureStrategy { public static final String JAVA_CARD_DL_STRATEGY = "JavaCardDLStrategy"; - private static final int IN_EQ_SIMP_NON_LIN_COST = 1000; - private static final int POLY_DIVISION_COST = -2250; - protected final StrategyProperties strategyProperties; private final RuleSetDispatchFeature costComputationDispatcher; @@ -239,8 +228,8 @@ private Feature oneStepSimplificationFeature(Feature cost) { // ////////////////////////////////////////////////////////////////////////// private RuleSetDispatchFeature setupCostComputationF() { - final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); final LocSetLDT locSetLDT = getServices().getTypeConverter().getLocSetLDT(); + final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); @@ -475,11 +464,6 @@ private RuleSetDispatchFeature setupCostComputationF() { setupUserTaclets(d); - setupArithPrimaryCategories(d); - setupPolySimp(d, numbers); - setupInEqSimp(d, numbers); - - setupDefOpsPrimaryCategories(d); setupSystemInvariantSimp(d); @@ -497,15 +481,6 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "pullOutQuantifierEx", inftyConst()); } - // For taclets that need instantiation, but where the instantiation is - // deterministic and does not have to be repeated at a later point, we - // setup the same feature terms as in the instantiation method. The - // definitions in setupInstantiationWithoutRetry should - // give cost infinity to those incomplete rule applications that will - // never be instantiated (so that these applications can be removed from - // the queue and do not have to be considered again). - setupInstantiationWithoutRetry(d); - // chrisg: The following rule, if active, must be applied delta rules. if (autoInductionEnabled()) { bindRuleSet(d, "auto_induction", -6500); // chrisg @@ -713,18 +688,6 @@ private void setupSystemInvariantSimp(RuleSetDispatchFeature d) { // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// - private boolean arithNonLinInferences() { - return StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); - } - - protected boolean arithDefOps() { - return StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)) - || StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); - } - private boolean instQuantifiersWithQueries() { return StrategyProperties.QUANTIFIERS_INSTANTIATE .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); @@ -1107,729 +1070,6 @@ private void setupQuantifierInstantiationApproval(RuleSetDispatchFeature d) { } } - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // Handling of arithmetic - // - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - - private void setupArithPrimaryCategories(RuleSetDispatchFeature d) { - // Gaussian elimination + Euclidian algorithm for linear equations; - // Buchberger's algorithmus for handling polynomial equations over - // the integers - - bindRuleSet(d, "polySimp_expand", -4500); - bindRuleSet(d, "polySimp_directEquations", -3000); - bindRuleSet(d, "polySimp_pullOutGcd", -2250); - bindRuleSet(d, "polySimp_leftNonUnit", -2000); - bindRuleSet(d, "polySimp_saturate", 0); - - // Omega test for handling linear arithmetic and inequalities over the - // integers; cross-multiplication + case distinctions for nonlinear - // inequalities - - bindRuleSet(d, "inEqSimp_expand", -4400); - bindRuleSet(d, "inEqSimp_directInEquations", -2900); - bindRuleSet(d, "inEqSimp_propagation", -2400); - bindRuleSet(d, "inEqSimp_pullOutGcd", -2150); - bindRuleSet(d, "inEqSimp_saturate", -1900); - bindRuleSet(d, "inEqSimp_forNormalisation", -1100); - bindRuleSet(d, "inEqSimp_special_nonLin", -1400); - - if (arithNonLinInferences()) { - bindRuleSet(d, "inEqSimp_nonLin", IN_EQ_SIMP_NON_LIN_COST); - } else { - bindRuleSet(d, "inEqSimp_nonLin", inftyConst()); - } - // polynomial division, simplification of fractions and mods - bindRuleSet(d, "polyDivision", POLY_DIVISION_COST); - - } - - private void setupPolySimp(RuleSetDispatchFeature d, IntegerLDT numbers) { - - // category "expansion" (normalising polynomial terms) - - bindRuleSet(d, "polySimp_elimSubNeg", longConst(-120)); - - bindRuleSet(d, "polySimp_homo", - add(applyTF("homoRight", add(not(tf.zeroLiteral), tf.polynomial)), - or(applyTF("homoLeft", or(tf.addF, tf.negMonomial)), - not(monSmallerThan("homoRight", "homoLeft", numbers))), - longConst(-120))); - - bindRuleSet(d, "polySimp_pullOutFactor", add(applyTFNonStrict("pullOutLeft", tf.literal), - applyTFNonStrict("pullOutRight", tf.literal), longConst(-120))); - - bindRuleSet(d, "polySimp_elimOneLeft", -120); - - bindRuleSet(d, "polySimp_elimOneRight", -120); - - bindRuleSet(d, "polySimp_mulOrder", add(applyTF("commRight", tf.monomial), or( - applyTF("commLeft", tf.addF), - add(applyTF("commLeft", tf.atom), atomSmallerThan("commLeft", "commRight", numbers))), - longConst(-100))); - - bindRuleSet(d, "polySimp_mulAssoc", - SumFeature.createSum(applyTF("mulAssocMono0", tf.monomial), - applyTF("mulAssocMono1", tf.monomial), applyTF("mulAssocAtom", tf.atom), - longConst(-80))); - - bindRuleSet(d, "polySimp_addOrder", - SumFeature.createSum(applyTF("commLeft", tf.monomial), - applyTF("commRight", tf.polynomial), - monSmallerThan("commRight", "commLeft", numbers), longConst(-60))); - - bindRuleSet(d, "polySimp_addAssoc", - SumFeature.createSum(applyTF("addAssocPoly0", tf.polynomial), - applyTF("addAssocPoly1", tf.polynomial), applyTF("addAssocMono", tf.monomial), - longConst(-10))); - - bindRuleSet(d, "polySimp_dist", - SumFeature.createSum(applyTF("distSummand0", tf.polynomial), - applyTF("distSummand1", tf.polynomial), - ifZero(applyTF("distCoeff", tf.monomial), longConst(-15), - applyTF("distCoeff", tf.polynomial)), - applyTF("distSummand0", tf.polynomial), - - applyTF("distSummand1", tf.polynomial), longConst(-35))); - - // category "direct equations" - - bindRuleSet(d, "polySimp_balance", - SumFeature - .createSum(applyTF("sepResidue", tf.polynomial), - ifZero(isInstantiated("sepPosMono"), - add(applyTF("sepPosMono", tf.nonNegMonomial), - monSmallerThan("sepResidue", "sepPosMono", numbers))), - ifZero(isInstantiated("sepNegMono"), - add(applyTF("sepNegMono", tf.negMonomial), - monSmallerThan("sepResidue", "sepNegMono", numbers))), - longConst(-30))); - - bindRuleSet(d, "polySimp_normalise", add(applyTF("invertRight", tf.zeroLiteral), - applyTF("invertLeft", tf.negMonomial), longConst(-30))); - - // application of equations: some specialised rules that handle - // monomials and their coefficients properly - - final TermBuffer eqLeft = new TermBuffer(); - final TermBuffer focus = new TermBuffer(); - - final TermFeature atLeastTwoLCEquation = - opSub(Equality.EQUALS, opSub(tf.mul, tf.atom, tf.atLeastTwoLiteral), tf.intF); - - final Feature validEqApplication = add(not(eq(eqLeft, focus)), - // otherwise, the normal equation rules can and should - // be used - ifZero(applyTF(AssumptionProjection.create(0), atLeastTwoLCEquation), - add(FocusInAntecFeature.getInstance(), - applyTF(FocusFormulaProjection.INSTANCE, atLeastTwoLCEquation))), - ReducibleMonomialsFeature.createReducible(focus, eqLeft)); - - final Feature eqMonomialFeature = add(not(directlyBelowSymbolAtIndex(tf.mul, -1)), - ifZero(MatchedAssumesFeature.INSTANCE, let(focus, FocusProjection.create(0), - let(eqLeft, sub(AssumptionProjection.create(0), 0), validEqApplication)))); - - bindRuleSet(d, "polySimp_applyEq", add(eqMonomialFeature, longConst(1))); - - bindRuleSet(d, "polySimp_applyEqRigid", add(eqMonomialFeature, longConst(2))); - - // - bindRuleSet(d, "defOps_expandModulo", - add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(-600))); - - // category "saturate" - - bindRuleSet(d, "polySimp_critPair", - ifZero(MatchedAssumesFeature.INSTANCE, - add(monSmallerThan("cpLeft1", "cpLeft2", numbers), - not(TrivialMonomialLCRFeature.create(instOf("cpLeft1"), instOf("cpLeft2")))))); - } - - // For taclets that need instantiation, but where the instantiation is - // deterministic and does not have to be repeated at a later point, we - // setup the same feature terms as in the instantiation method. The - // definitions in setupInstantiationWithoutRetry should - // give cost infinity to those incomplete rule applications that will - // never be instantiated (so that these applications can be removed from - // the queue and do not have to be considered again). - private void setupPolySimpInstantiationWithoutRetry(RuleSetDispatchFeature d) { - final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); - - // category "direct equations" - - setupPullOutGcd(d, "polySimp_pullOutGcd", false); - - // category "polynomial division" - - setupDivModDivision(d); - - // category "handling of equations with non-unit-coefficients on - // left-hand side" - - bindRuleSet(d, "polySimp_newSym", - ifZero(not(isInstantiated("newSymDef")), SumFeature.createSum( - applyTF("newSymLeft", tf.atom), applyTF("newSymLeftCoeff", tf.atLeastTwoLiteral), - applyTF("newSymRight", tf.polynomial), instantiate("newSymDef", - MonomialColumnOp.create(instOf("newSymLeftCoeff"), instOf("newSymRight")))))); - - final TermBuffer divisor = new TermBuffer(); - final TermBuffer dividend = new TermBuffer(); - - bindRuleSet(d, "polySimp_applyEqPseudo", - add(applyTF("aePseudoTargetLeft", tf.monomial), - applyTF("aePseudoTargetRight", tf.polynomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(DiffFindAndIfFeature.INSTANCE, - applyTF("aePseudoLeft", add(tf.nonCoeffMonomial, not(tf.atom))), - applyTF("aePseudoLeftCoeff", tf.atLeastTwoLiteral), - applyTF("aePseudoRight", tf.polynomial), - MonomialsSmallerThanFeature.create(instOf("aePseudoRight"), - instOf("aePseudoLeft"), numbers), - let(divisor, instOf("aePseudoLeft"), - let(dividend, instOf("aePseudoTargetLeft"), - add(ReducibleMonomialsFeature.createReducible(dividend, divisor), - instantiate("aePseudoTargetFactor", - ReduceMonomialsProjection.create(dividend, divisor))))))))); - } - - private void setupNewSymApproval(RuleSetDispatchFeature d, IntegerLDT numbers) { - final TermBuffer antecFor = new TermBuffer(); - final Feature columnOpEq = applyTF(antecFor, - opSub(tf.eq, opSub(tf.mul, tf.atom, tf.atLeastTwoLiteral), tf.polynomial)); - final Feature biggerLeftSide = - MonomialsSmallerThanFeature.create(instOf("newSymLeft"), - subAt(antecFor, PosInTerm.getTopLevel().down(0).down(0)), numbers); - bindRuleSet(d, "polySimp_newSym", add(isInstantiated("newSymDef"), sum(antecFor, - SequentFormulasGenerator.antecedent(), not(add(columnOpEq, biggerLeftSide))))); - } - - private void setupPullOutGcd(RuleSetDispatchFeature d, String ruleSet, boolean roundingUp) { - final TermBuffer gcd = new TermBuffer(); - - final Feature instantiateDivs; - if (roundingUp) { - instantiateDivs = add( - instantiate("elimGcdLeftDiv", - DividePolynomialsProjection.createRoundingUp(gcd, instOf("elimGcdLeft"))), - instantiate("elimGcdRightDiv", - DividePolynomialsProjection.createRoundingUp(gcd, instOf("elimGcdRight")))); - } else { - instantiateDivs = add( - instantiate("elimGcdLeftDiv", - DividePolynomialsProjection.createRoundingDown(gcd, instOf("elimGcdLeft"))), - instantiate("elimGcdRightDiv", - DividePolynomialsProjection.createRoundingDown(gcd, instOf("elimGcdRight")))); - } - bindRuleSet(d, ruleSet, - add(applyTF("elimGcdLeft", tf.nonNegMonomial), applyTF("elimGcdRight", tf.polynomial), - let(gcd, CoeffGcdProjection.create(instOf("elimGcdLeft"), instOf("elimGcdRight")), - add(applyTF(gcd, tf.atLeastTwoLiteral), instantiate("elimGcd", gcd), - instantiateDivs)))); - } - - private void setupInEqSimp(RuleSetDispatchFeature d, IntegerLDT numbers) { - - // category "expansion" (normalising inequations) - - bindRuleSet(d, "inEqSimp_moveLeft", -90); - - bindRuleSet(d, "inEqSimp_makeNonStrict", -80); - - bindRuleSet(d, "inEqSimp_commute", - SumFeature.createSum(applyTF("commRight", tf.monomial), - applyTF("commLeft", tf.polynomial), - monSmallerThan("commLeft", "commRight", numbers), longConst(-40))); - - // this is copied from "polySimp_homo" - bindRuleSet(d, "inEqSimp_homo", - add(applyTF("homoRight", add(not(tf.zeroLiteral), tf.polynomial)), - or(applyTF("homoLeft", or(tf.addF, tf.negMonomial)), - not(monSmallerThan("homoRight", "homoLeft", numbers))))); - - // category "direct inequations" - - // this is copied from "polySimp_balance" - bindRuleSet(d, "inEqSimp_balance", - add(applyTF("sepResidue", tf.polynomial), - ifZero(isInstantiated("sepPosMono"), - add(applyTF("sepPosMono", tf.nonNegMonomial), - monSmallerThan("sepResidue", "sepPosMono", numbers))), - ifZero(isInstantiated("sepNegMono"), add(applyTF("sepNegMono", tf.negMonomial), - monSmallerThan("sepResidue", "sepNegMono", numbers))))); - - // this is copied from "polySimp_normalise" - bindRuleSet(d, "inEqSimp_normalise", - add(applyTF("invertRight", tf.zeroLiteral), applyTF("invertLeft", tf.negMonomial))); - - // category "saturate" - - bindRuleSet(d, "inEqSimp_antiSymm", longConst(-20)); - - bindRuleSet(d, "inEqSimp_exactShadow", - SumFeature.createSum(applyTF("esLeft", tf.nonCoeffMonomial), - applyTFNonStrict("esCoeff2", tf.nonNegLiteral), applyTF("esRight2", tf.polynomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(applyTFNonStrict("esCoeff1", tf.nonNegLiteral), - applyTF("esRight1", tf.polynomial), - not(PolynomialValuesCmpFeature.leq(instOf("esRight2"), instOf("esRight1"), - instOfNonStrict("esCoeff1"), instOfNonStrict("esCoeff2"))))))); - - // category "propagation" - - bindRuleSet(d, "inEqSimp_contradInEqs", - add(applyTF("contradLeft", tf.monomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(DiffFindAndIfFeature.INSTANCE, - applyTF("contradRightSmaller", tf.polynomial), - applyTF("contradRightBigger", tf.polynomial), - applyTFNonStrict("contradCoeffSmaller", tf.posLiteral), - applyTFNonStrict("contradCoeffBigger", tf.posLiteral), - PolynomialValuesCmpFeature.lt(instOf("contradRightSmaller"), - instOf("contradRightBigger"), instOfNonStrict("contradCoeffBigger"), - instOfNonStrict("contradCoeffSmaller")))))); - - bindRuleSet(d, "inEqSimp_contradEqs", - add(applyTF("contradLeft", tf.monomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(applyTF("contradRightSmaller", tf.polynomial), - applyTF("contradRightBigger", tf.polynomial), PolynomialValuesCmpFeature - .lt(instOf("contradRightSmaller"), instOf("contradRightBigger")))), - longConst(-60))); - - bindRuleSet(d, "inEqSimp_strengthen", longConst(-30)); - - bindRuleSet(d, "inEqSimp_subsumption", - add(applyTF("subsumLeft", tf.monomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(DiffFindAndIfFeature.INSTANCE, - applyTF("subsumRightSmaller", tf.polynomial), - applyTF("subsumRightBigger", tf.polynomial), - applyTFNonStrict("subsumCoeffSmaller", tf.posLiteral), - applyTFNonStrict("subsumCoeffBigger", tf.posLiteral), - PolynomialValuesCmpFeature.leq(instOf("subsumRightSmaller"), - instOf("subsumRightBigger"), instOfNonStrict("subsumCoeffBigger"), - instOfNonStrict("subsumCoeffSmaller")))))); - - // category "handling of non-linear inequations" - - if (arithNonLinInferences()) { - setupMultiplyInequations(d, longConst(100)); - - bindRuleSet(d, "inEqSimp_split_eq", add(TopLevelFindFeature.SUCC, longConst(-100))); - - bindRuleSet(d, "inEqSimp_signCases", not(isInstantiated("signCasesLeft"))); - } - - // category "normalisation of formulas" - // (e.g., quantified formulas, where the normal sequent calculus - // does not do any normalisation) - - bindRuleSet(d, "inEqSimp_and_contradInEqs", - SumFeature.createSum(applyTF("contradLeft", tf.monomial), - applyTF("contradRightSmaller", tf.polynomial), - applyTF("contradRightBigger", tf.polynomial), PolynomialValuesCmpFeature - .lt(instOf("contradRightSmaller"), instOf("contradRightBigger")))); - - bindRuleSet(d, "inEqSimp_andOr_subsumption", - SumFeature.createSum(applyTF("subsumLeft", tf.monomial), - applyTF("subsumRightSmaller", tf.polynomial), - applyTF("subsumRightBigger", tf.polynomial), PolynomialValuesCmpFeature - .leq(instOf("subsumRightSmaller"), instOf("subsumRightBigger")))); - - bindRuleSet(d, "inEqSimp_and_subsumptionEq", - SumFeature.createSum(applyTF("subsumLeft", tf.monomial), - applyTF("subsumRightSmaller", tf.polynomial), - applyTF("subsumRightBigger", tf.polynomial), PolynomialValuesCmpFeature - .lt(instOf("subsumRightSmaller"), instOf("subsumRightBigger")))); - - final Term tOne = getServices().getTermBuilder().zTerm("1"); - final TermBuffer one = new TermBuffer() { - @Override - public void setContent(Term term, MutableState mState) {} - - @Override - public @NonNull Term getContent(MutableState mState) { - return tOne; - } - - @Override - public @NonNull Term toTerm(RuleApp app, PosInOccurrence pos, - Goal goal, MutableState mState) { - return tOne; - } - }; - - final JTerm tTwo = getServices().getTermBuilder().zTerm("2"); - final TermBuffer two = new TermBuffer() { - @Override - public void setContent(Term term, MutableState mState) {} - - @Override - public @NonNull Term getContent(MutableState mState) { - return tTwo; - } - - @Override - public @NonNull Term toTerm(RuleApp app, PosInOccurrence pos, - Goal goal, MutableState mState) { - return tTwo; - } - }; - - bindRuleSet(d, "inEqSimp_or_tautInEqs", - SumFeature.createSum(applyTF("tautLeft", tf.monomial), - applyTF("tautRightSmaller", tf.polynomial), - applyTF("tautRightBigger", tf.polynomial), - PolynomialValuesCmpFeature.leq(instOf("tautRightSmaller"), - opTerm(numbers.getAdd(), one, instOf("tautRightBigger"))))); - - bindRuleSet(d, "inEqSimp_or_weaken", - SumFeature.createSum(applyTF("weakenLeft", tf.monomial), - applyTF("weakenRightSmaller", tf.polynomial), - applyTF("weakenRightBigger", tf.polynomial), - PolynomialValuesCmpFeature.eq( - opTerm(numbers.getAdd(), one, instOf("weakenRightSmaller")), - instOf("weakenRightBigger")))); - - bindRuleSet(d, "inEqSimp_or_antiSymm", - SumFeature.createSum(applyTF("antiSymmLeft", tf.monomial), - applyTF("antiSymmRightSmaller", tf.polynomial), - applyTF("antiSymmRightBigger", tf.polynomial), - PolynomialValuesCmpFeature.eq( - opTerm(numbers.getAdd(), two, instOf("antiSymmRightSmaller")), - instOf("antiSymmRightBigger")))); - - } - - private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature notAllowedF) { - final TermBuffer intRel = new TermBuffer(); - - /* - * final Feature partiallyBounded = not ( sum ( intRel, SequentFormulasGenerator.sequent (), - * not ( add ( applyTF ( intRel, tf.intRelation ), InEquationMultFeature .partiallyBounded ( - * instOf ( "multLeft" ), instOf ( "multFacLeft" ), sub ( intRel, 0 ) ) ) ) ) ); - */ - - final Feature totallyBounded = not(sum(intRel, SequentFormulasGenerator.sequent(), - not(add(applyTF(intRel, tf.intRelation), InEquationMultFeature - .totallyBounded(instOf("multLeft"), instOf("multFacLeft"), sub(intRel, 0)))))); - - final Feature exactlyBounded = not(sum(intRel, SequentFormulasGenerator.sequent(), - not(add(applyTF(intRel, tf.intRelation), InEquationMultFeature - .exactlyBounded(instOf("multLeft"), instOf("multFacLeft"), sub(intRel, 0)))))); - - // this is a bit hackish - // - // really, one would need a possibility to express that the cost - // computation for the rule application should be post-poned (and - // repeated at a later point) if the product of the left sides does not - // have any similarity with existing left sides - // (AllowInEquationMultiplication returns false). We - // simulate this by returning non-infinite costs here, but by declining - // the rule application in isApprovedApp). This is not - // perfect, because it is not possible to distinguish between the - // re-cost-computation delay and the normal costs for a rule application - bindRuleSet(d, "inEqSimp_nonLin_multiply", add(applyTF("multLeft", tf.nonNegMonomial), - applyTF("multRight", tf.polynomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(applyTF("multFacLeft", tf.nonNegMonomial), - ifZero(applyTF("multRight", tf.literal), longConst(-100)), - ifZero(applyTF("multFacRight", tf.literal), longConst(-100), - applyTF("multFacRight", tf.polynomial)), - /* - * ifZero ( applyTF ( "multRight", tf.literal ), longConst ( -100 ), applyTF ( - * "multRight", tf.polynomial ) ), ifZero ( applyTF ( "multFacRight", tf.literal - * ), longConst ( -100 ), applyTF ( "multFacRight", tf.polynomial ) ), - */ - not(TermSmallerThanFeature.create(FocusProjection.create(0), - AssumptionProjection.create(0))), - ifZero(exactlyBounded, longConst(0), - ifZero(totallyBounded, longConst(100), notAllowedF)) - /* - * ifZero ( partiallyBounded, longConst ( 400 ), notAllowedF ) ) ), - */ - /* - * applyTF ( "multLeft", rec ( tf.mulF, longTermConst ( 20 ) ) ), applyTF ( - * "multFacLeft", rec ( tf.mulF, longTermConst ( 20 ) ) ), applyTF ( "multRight", - * rec ( tf.addF, longTermConst ( 4 ) ) ), applyTF ( "multFacRight", rec ( tf.addF, - * longTermConst ( 4 ) ) ), - */ - ), notAllowedF))); - } - - private void setupInEqSimpInstantiation(RuleSetDispatchFeature d) { - // category "handling of non-linear inequations" - - setupSquaresAreNonNegative(d); - - if (arithNonLinInferences()) { - setupInEqCaseDistinctions(d); - } - } - - // For taclets that need instantiation, but where the instantiation is - // deterministic and does not have to be repeated at a later point, we - // setup the same feature terms as in the instantiation method. The - // definitions in setupInstantiationWithoutRetry should - // give cost infinity to those incomplete rule applications that will - // never be instantiated (so that these applications can be removed from - // the queue and do not have to be considered again). - private void setupInEqSimpInstantiationWithoutRetry(RuleSetDispatchFeature d) { - // category "direct inequations" - - setupPullOutGcd(d, "inEqSimp_pullOutGcd_leq", false); - setupPullOutGcd(d, "inEqSimp_pullOutGcd_geq", true); - - // more efficient (but not confluent) versions for the antecedent - bindRuleSet(d, "inEqSimp_pullOutGcd_antec", -10); - - // category "handling of non-linear inequations" - - final TermBuffer divisor = new TermBuffer(); - final TermBuffer dividend = new TermBuffer(); - - bindRuleSet(d, "inEqSimp_nonLin_divide", SumFeature.createSum( - applyTF("divProd", tf.nonCoeffMonomial), - applyTFNonStrict("divProdBoundNonPos", tf.nonPosLiteral), - applyTFNonStrict("divProdBoundNonNeg", tf.nonNegLiteral), - ifZero(MatchedAssumesFeature.INSTANCE, - let(divisor, instOf("divX"), let(dividend, instOf("divProd"), - SumFeature.createSum(applyTF(divisor, tf.nonCoeffMonomial), - not(eq(dividend, divisor)), applyTFNonStrict("divXBoundPos", tf.posLiteral), - applyTFNonStrict("divXBoundNeg", tf.negLiteral), - ReducibleMonomialsFeature.createReducible(dividend, divisor), instantiate( - "divY", ReduceMonomialsProjection.create(dividend, divisor)))))))); - - setupNonLinTermIsPosNeg(d, "inEqSimp_nonLin_pos", true); - setupNonLinTermIsPosNeg(d, "inEqSimp_nonLin_neg", false); - } - - private void setupNonLinTermIsPosNeg(RuleSetDispatchFeature d, String ruleSet, boolean pos) { - final TermBuffer divisor = new TermBuffer(); - final TermBuffer dividend = new TermBuffer(); - final TermBuffer quotient = new TermBuffer(); - final TermBuffer antecFor = new TermBuffer(); - - bindRuleSet(d, ruleSet, - SumFeature - .createSum(applyTF("divProd", tf.nonCoeffMonomial), - applyTFNonStrict("divProdBoundPos", tf.posLiteral), - applyTFNonStrict("divProdBoundNeg", tf.negLiteral), - ifZero(MatchedAssumesFeature.INSTANCE, - let(divisor, instOf("divX"), let(dividend, instOf("divProd"), - SumFeature.createSum(applyTF(divisor, tf.nonCoeffMonomial), - not(applyTF(dividend, eq(divisor))), - applyTFNonStrict("divXBoundNonPos", tf.nonPosLiteral), - applyTFNonStrict("divXBoundNonNeg", tf.nonNegLiteral), - ReducibleMonomialsFeature.createReducible(dividend, divisor), - let(quotient, - ReduceMonomialsProjection.create(dividend, divisor), add( - sum(antecFor, SequentFormulasGenerator.antecedent(), - not(applyTF(antecFor, - pos ? opSub(tf.geq, eq(quotient), tf.posLiteral) - : opSub(tf.leq, eq(quotient), - tf.negLiteral)))), - instantiate("divY", quotient))))))))); - } - - private void setupSquaresAreNonNegative(RuleSetDispatchFeature d) { - final TermBuffer intRel = new TermBuffer(); - final TermBuffer product = new TermBuffer(); - final TermBuffer factor = new TermBuffer(); - - final Feature productContainsSquare = - applyTF(sub(product, 0), or(eq(factor), opSub(tf.mul, any(), eq(factor)))); - final Feature productIsProduct = applyTF(product, opSub(tf.mul, any(), not(tf.mulF))); - - bindRuleSet(d, "inEqSimp_nonNegSquares", - forEach(intRel, SequentFormulasGenerator.sequent(), - ifZero(applyTF(intRel, tf.intRelation), - forEach(product, SubtermGenerator.leftTraverse(sub(intRel, 0), tf.mulF), - ifZero(productIsProduct, let(factor, sub(product, 1), - ifZero(productContainsSquare, instantiate("squareFac", factor)))))))); - } - - private void setupInEqCaseDistinctions(RuleSetDispatchFeature d) { - final TermBuffer intRel = new TermBuffer(); - final TermBuffer atom = new TermBuffer(); - final TermBuffer rootInf = new TermBuffer(); - - final Feature posNegSplitting = forEach(intRel, SequentFormulasGenerator.antecedent(), - add(applyTF(intRel, tf.intRelation), - forEach(atom, SubtermGenerator.leftTraverse(sub(intRel, 0), tf.mulF), - SumFeature.createSum(applyTF(atom, add(tf.atom, not(tf.literal))), - allowPosNegCaseDistinction(atom), instantiate("signCasesLeft", atom), - longConst(IN_EQ_SIMP_NON_LIN_COST + 200) - // , - // applyTF ( atom, rec ( any (), - // longTermConst ( 5 ) ) ) - )))); - - bindRuleSet(d, "inEqSimp_signCases", posNegSplitting); - - final Feature strengthening = forEach(intRel, SequentFormulasGenerator.antecedent(), - SumFeature.createSum( - applyTF(intRel, add(or(tf.geqF, tf.leqF), sub(tf.atom, tf.literal))), - instantiate("cutFormula", opTerm(tf.eq, sub(intRel, 0), sub(intRel, 1))), - longConst(IN_EQ_SIMP_NON_LIN_COST + 300) - // , - // applyTF ( sub ( intRel, 0 ), - // rec ( any (), longTermConst ( 5 ) ) ) - )); - - final Feature rootInferences = forEach(intRel, SequentFormulasGenerator.antecedent(), - add(isRootInferenceProducer(intRel), - forEach(rootInf, RootsGenerator.create(intRel, getServices()), - add(instantiate("cutFormula", rootInf), - ifZero(applyTF(rootInf, op(Junctor.OR)), longConst(50)), - ifZero(applyTF(rootInf, op(Junctor.AND)), longConst(20)))), - longConst(IN_EQ_SIMP_NON_LIN_COST))); - - // noinspection unchecked - bindRuleSet(d, "cut", oneOf(new Feature[] { strengthening, rootInferences })); - } - - private Feature isRootInferenceProducer(TermBuffer intRel) { - return applyTF(intRel, add(tf.intRelation, sub(tf.nonCoeffMonomial, tf.literal))); - } - - private Feature allowPosNegCaseDistinction(TermBuffer atom) { - final TermBuffer antecFor = new TermBuffer(); - final TermFeature eqAtom = eq(atom); - - return add(not(succIntEquationExists()), - sum(antecFor, SequentFormulasGenerator.antecedent(), - not(applyTF(antecFor, or(opSub(tf.eq, eqAtom, any()), - opSub(tf.leq, eqAtom, tf.negLiteral), opSub(tf.geq, eqAtom, tf.posLiteral)))))); - } - - private Feature allowInEqStrengthening(TermBuffer atom, TermBuffer literal) { - final TermBuffer antecFor = new TermBuffer(); - - return add(not(succIntEquationExists()), - not(sum(antecFor, SequentFormulasGenerator.antecedent(), - not(applyTF(antecFor, add(or(tf.leqF, tf.geqF), sub(eq(atom), eq(literal)))))))); - } - - private Feature succIntEquationExists() { - final TermBuffer succFor = new TermBuffer(); - - return not(sum(succFor, SequentFormulasGenerator.succedent(), - not(applyTF(succFor, tf.intEquation)))); - } - - protected final Services getServices() { - return getProof().getServices(); - } - - private void setupInEqCaseDistinctionsApproval(RuleSetDispatchFeature d) { - final TermBuffer atom = new TermBuffer(); - final TermBuffer literal = new TermBuffer(); - final TermBuffer intRel = new TermBuffer(); - final TermBuffer rootInf = new TermBuffer(); - - bindRuleSet(d, "inEqSimp_signCases", add(isInstantiated("signCasesLeft"), - let(atom, instOf("signCasesLeft"), allowPosNegCaseDistinction(atom)))); - - // this is somewhat ugly. we should introduce some concept of "tagging" - // rule application so that they can be recognised again later - bindRuleSet(d, "cut", - add(isInstantiated("cutFormula"), or( - not(sum(intRel, SequentFormulasGenerator.antecedent(), - ifZero(isRootInferenceProducer(intRel), - sum(rootInf, RootsGenerator.create(intRel, getServices()), - not(eq(instOf("cutFormula"), rootInf)))))), - ifZero(applyTF("cutFormula", opSub(tf.eq, tf.atom, tf.literal)), - let(atom, sub(instOf("cutFormula"), 0), let(literal, - sub(instOf("cutFormula"), 1), allowInEqStrengthening(atom, literal))))))); - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // Axiomatisation and algorithms for further arithmetic operations: - // division, modulus, modular Java operations - // - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - - private void setupDefOpsPrimaryCategories(RuleSetDispatchFeature d) { - - if (arithDefOps()) { - // the axiom defining division only has to be inserted once, because - // it adds equations to the antecedent - bindRuleSet(d, "defOps_div", - SumFeature.createSum(NonDuplicateAppModPositionFeature.INSTANCE, - applyTF("divNum", tf.polynomial), applyTF("divDenom", tf.polynomial), - applyTF("divNum", tf.notContainsDivMod), - applyTF("divDenom", tf.notContainsDivMod), - ifZero(isBelow(ff.modalOperator), longConst(200)))); - - bindRuleSet(d, "defOps_jdiv", - SumFeature.createSum(NonDuplicateAppModPositionFeature.INSTANCE, - applyTF("divNum", tf.polynomial), applyTF("divDenom", tf.polynomial), - applyTF("divNum", tf.notContainsDivMod), - applyTF("divDenom", tf.notContainsDivMod), - ifZero(isBelow(ff.modalOperator), longConst(200)))); - - bindRuleSet(d, "defOps_jdiv_inline", add(applyTF("divNum", tf.literal), - applyTF("divDenom", tf.polynomial), longConst(-5000))); - - setupDefOpsExpandMod(d); - - bindRuleSet(d, "defOps_expandRanges", -8000); - bindRuleSet(d, "defOps_expandJNumericOp", -500); - bindRuleSet(d, "defOps_modHomoEq", -5000); - } else { - bindRuleSet(d, "defOps_div", inftyConst()); - bindRuleSet(d, "defOps_jdiv", inftyConst()); - - bindRuleSet(d, "defOps_jdiv_inline", add(applyTF("divNum", tf.literal), - applyTF("divDenom", tf.literal), longConst(-4000))); - - bindRuleSet(d, "defOps_mod", add(applyTF("divNum", tf.literal), - applyTF("divDenom", tf.literal), longConst(-4000))); - - bindRuleSet(d, "defOps_expandRanges", inftyConst()); - bindRuleSet(d, "defOps_expandJNumericOp", inftyConst()); - bindRuleSet(d, "defOps_modHomoEq", inftyConst()); - } - - } - - private void setupDefOpsExpandMod(RuleSetDispatchFeature d) { - final TermBuffer superTerm = new TermBuffer(); - - final Feature subsumedModulus = - add(applyTF(superTerm, sub(opSub(tf.mod, any(), tf.literal), tf.zeroLiteral)), - PolynomialValuesCmpFeature.divides(instOf("divDenom"), sub(sub(superTerm, 0), 1))); - - final Feature exSubsumedModulus = add(applyTF("divDenom", tf.literal), - not(sum(superTerm, - SuperTermGenerator.upwardsWithIndex(sub(or(tf.addF, tf.mulF), any()), - getServices()), - not(subsumedModulus)))); - - bindRuleSet(d, "defOps_mod", - ifZero(add(applyTF("divNum", tf.literal), applyTF("divDenom", tf.literal)), - longConst(-4000), - SumFeature.createSum(applyTF("divNum", tf.polynomial), - applyTF("divDenom", tf.polynomial), - ifZero(isBelow(ff.modalOperator), exSubsumedModulus, - or(add(applyTF("divNum", tf.notContainsDivMod), - applyTF("divDenom", tf.notContainsDivMod)), exSubsumedModulus)), - longConst(-3500)))); - } - - protected final Feature isBelow(TermFeature t) { - final TermBuffer superTerm = new TermBuffer(); - return not(sum(superTerm, SuperTermGenerator.upwards(any(), getServices()), - not(applyTF(superTerm, t)))); - } protected final Feature onlyInScopeOfQuantifiers() { final TermBuffer buf = new TermBuffer(); @@ -1844,48 +1084,6 @@ protected Feature notBelowQuantifier() { not(applyTF(superFor, OperatorClassTF.create(Quantifier.class))))); } - private void setupDivModDivision(RuleSetDispatchFeature d) { - - final TermBuffer denomLC = new TermBuffer(); - final TermBuffer numTerm = new TermBuffer(); - final TermBuffer divCoeff = new TermBuffer(); - - // exact polynomial division - - final Feature checkNumTerm = ifZero( - add(not(applyTF(numTerm, tf.addF)), - ReducibleMonomialsFeature.createReducible(numTerm, denomLC)), - add(instantiate("polyDivCoeff", ReduceMonomialsProjection.create(numTerm, denomLC)), - inftyConst())); - - final Feature isReduciblePoly = - sum(numTerm, SubtermGenerator.rightTraverse(instOf("divNum"), tf.addF), checkNumTerm); - - // polynomial division modulo equations of the antecedent - - final Feature checkCoeffE = ifZero(contains(divCoeff, FocusProjection.create(0)), - // do not apply if the result contains the original term - longConst(0), add(instantiate("polyDivCoeff", divCoeff), inftyConst())); - - final Feature isReduciblePolyE = - sum(numTerm, SubtermGenerator.rightTraverse(instOf("divNum"), tf.addF), - ifZero(applyTF(numTerm, tf.addF), longConst(0), sum(divCoeff, - MultiplesModEquationsGenerator.create(numTerm, denomLC), checkCoeffE))); - - bindRuleSet(d, "defOps_divModPullOut", - SumFeature.createSum( - not(add(applyTF("divNum", tf.literal), applyTF("divDenom", tf.literal))), - applyTF("divNum", tf.polynomial), applyTF("divDenom", tf.polynomial), - ifZero(applyTF("divDenom", tf.addF), - let(denomLC, sub(instOf("divDenom"), 1), not(isReduciblePoly)), - let(denomLC, instOf("divDenom"), ifZero(isReduciblePoly, - // no possible division has been found so far - add(NotInScopeOfModalityFeature.INSTANCE, ifZero(isReduciblePolyE, - // try again later - longConst(-POLY_DIVISION_COST)))))), - longConst(100))); - - } // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// @@ -1914,35 +1112,6 @@ private RuleSetDispatchFeature setupApprovalDispatcher() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); - if (arithNonLinInferences()) { - setupMultiplyInequations(d, inftyConst()); - } - - // these taclets are not supposed to be applied with metavariable - // instantiations - // I'll keep it here for the moment as documentation, but comment it out - // as meta variables are no longer part of KeY 2.x - /* - * bindRuleSet ( d, "inEqSimp_pullOutGcd", isInstantiated ( "elimGcd" ) ); bindRuleSet ( d, - * "polySimp_pullOutGcd", isInstantiated ( "elimGcd" ) ); - * - * bindRuleSet ( d, "inEqSimp_nonNegSquares", isInstantiated ( "squareFac" ) ); bindRuleSet - * ( d, "inEqSimp_nonLin_divide", isInstantiated ( "divY" ) ); bindRuleSet ( d, - * "inEqSimp_nonLin_pos", isInstantiated ( "divY" ) ); bindRuleSet ( d, - * "inEqSimp_nonLin_neg", isInstantiated ( "divY" ) ); - * - * bindRuleSet ( d, "inEqSimp_signCases", isInstantiated ( "signCasesLeft" ) ); - */ - - setupNewSymApproval(d, numbers); - - bindRuleSet(d, "defOps_div", NonDuplicateAppModPositionFeature.INSTANCE); - bindRuleSet(d, "defOps_jdiv", NonDuplicateAppModPositionFeature.INSTANCE); - - if (arithNonLinInferences()) { - setupInEqCaseDistinctionsApproval(d); - } - bindRuleSet(d, "inReachableStateImplication", NonDuplicateAppModPositionFeature.INSTANCE); bindRuleSet(d, "limitObserver", NonDuplicateAppModPositionFeature.INSTANCE); bindRuleSet(d, "partialInvAxiom", NonDuplicateAppModPositionFeature.INSTANCE); @@ -2021,16 +1190,7 @@ private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); - setupQuantifierInstantiation(d); - - setupArithPrimaryCategories(d); - setupDefOpsPrimaryCategories(d); - - setupInstantiationWithoutRetry(d); - - setupInEqSimpInstantiation(d); - setClassAxiomInstantiation(d); disableInstantiate(); @@ -2053,18 +1213,6 @@ private void setClassAxiomInstantiation(final RuleSetDispatchFeature d) { bindRuleSet(d, "classAxiom", heapInstantiator); } - /** - * For taclets that need instantiation, but where the instantiation is deterministic and does - * not have to be repeated at a later point, we setup the same feature terms both in the cost - * computation method and in the instantiation method. The definitions in - * setupInstantiationWithoutRetry should give cost infinity to those incomplete - * rule applications that will never be instantiated (so that these applications can be removed - * from the queue and do not have to be considered again). - */ - private void setupInstantiationWithoutRetry(RuleSetDispatchFeature d) { - setupPolySimpInstantiationWithoutRetry(d); - setupInEqSimpInstantiationWithoutRetry(d); - } @Override public @NonNull Name name() { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index a828f7ef9a..1eac88125f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java @@ -455,7 +455,7 @@ private static OneOfStrategyPropertyDefinition getUserOptions() { @Override public Strategy<@NonNull Goal> create(Proof proof, StrategyProperties strategyProperties) { - return new JavaCardDLStrategy(proof, strategyProperties); + return new ModularJavaDLStrategy(proof, strategyProperties); } @Override diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java new file mode 100644 index 0000000000..8dc41296b1 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -0,0 +1,66 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import java.util.ArrayList; +import java.util.List; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; + +import org.key_project.logic.Name; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.RuleAppCost; + +import org.jspecify.annotations.NonNull; + +public class ModularJavaDLStrategy extends AbstractFeatureStrategy { + + public static final Name NAME = new Name("Modular JavaDL Strategy"); + + private final List strategies = new ArrayList<>(); + private final StrategyProperties strategyProperties; + + public ModularJavaDLStrategy(Proof proof, StrategyProperties strategyProperties) { + super(proof); + strategies.add(new JavaCardDLStrategy(proof, strategyProperties)); + strategies.add(new IntegerStrategy(proof, strategyProperties)); + this.strategyProperties = (StrategyProperties) strategyProperties.clone(); + } + + @Override + protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return strategies.stream().map(s -> s.instantiateApp(app, pio, goal, mState)).reduce( + longConst(0).computeCost(app, pio, goal, mState), + RuleAppCost::add); + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) + .equals(StrategyProperties.STOPMODE_NONCLOSE); + } + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return strategies.stream().allMatch(s -> s.isApprovedApp(app, pio, goal)); + } + + @Override + public Name name() { + return NAME; + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { + return strategies.stream().map(s -> s.computeCost(app, pos, goal, mState)).reduce( + longConst(0).computeCost(app, pos, goal, mState), + RuleAppCost::add); + } +} From a1a4dfc6fa6ed9b72736e256d80454f88fa0df8e Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Thu, 3 Jul 2025 16:55:00 +0200 Subject: [PATCH 02/62] Cleanup of IntegerStrategy --- .../ilkd/key/strategy/IntegerStrategy.java | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 5ef6017895..ceb70ead3d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -36,40 +36,58 @@ public class IntegerStrategy extends AbstractFeatureStrategy { - public static final Name NAME = new Name("Integer Strategy"); - private final RuleSetDispatchFeature costComputationDispatcher; - private final ArithTermFeatures tf; + /// Magic constants private static final int IN_EQ_SIMP_NON_LIN_COST = 1000; private static final int POLY_DIVISION_COST = -2250; - protected final StrategyProperties strategyProperties; - private final FormulaTermFeatures ff; + + /// The features defining the three phases: cost computation, approval, + /// additionalInstanceCreationAndEvaluation + private final RuleSetDispatchFeature costComputationDispatcher; private final RuleSetDispatchFeature approvalDispatcher; private final RuleSetDispatchFeature instantiationDispatcher; + /// Useful [TermFeature] collections + private final ArithTermFeatures tf; + private final FormulaTermFeatures ff; + + /// configuration options extracted from [StrategyProperties] + private final boolean nonLinearArithmeticEnabled; + private final boolean divAndModuloReasoningEnabled; + private final boolean stopAtFirstNonCloseableGoal; public IntegerStrategy(Proof proof, StrategyProperties strategyProperties) { super(proof); - this.strategyProperties = (StrategyProperties) strategyProperties.clone(); this.tf = new ArithTermFeatures(proof.getServices().getTypeConverter().getIntegerLDT()); this.ff = new FormulaTermFeatures(this.tf); + + // determine configuration + nonLinearArithmeticEnabled = StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + + divAndModuloReasoningEnabled = + nonLinearArithmeticEnabled || StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals( + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + + stopAtFirstNonCloseableGoal = + strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) + .equals(StrategyProperties.STOPMODE_NONCLOSE); + + // setup cost computations costComputationDispatcher = setupCostComputationF(); approvalDispatcher = setupApprovalDispatcher(); instantiationDispatcher = setupInstantiationF(); + } private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); - - setupArithPrimaryCategories(d); setupDefOpsPrimaryCategories(d); - setupInstantiationWithoutRetry(d); - setupInEqSimpInstantiation(d); disableInstantiate(); @@ -136,17 +154,19 @@ private RuleSetDispatchFeature setupCostComputationF() { } private boolean arithNonLinInferences() { - return StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + return nonLinearArithmeticEnabled; } - protected boolean arithDefOps() { - return StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)) - || StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + private boolean arithDefOps() { + return divAndModuloReasoningEnabled; } + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return stopAtFirstNonCloseableGoal; + } + + // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// // @@ -918,12 +938,6 @@ private void setupInstantiationWithoutRetry(RuleSetDispatchFeature d) { setupInEqSimpInstantiationWithoutRetry(d); } - @Override - public boolean isStopAtFirstNonCloseableGoal() { - return strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) - .equals(StrategyProperties.STOPMODE_NONCLOSE); - } - @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { return !(approvalDispatcher.computeCost(app, pio, goal, From 4c9a0ea426f688fc77db5b5c79fa72026cd92b4d Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Thu, 3 Jul 2025 17:38:33 +0200 Subject: [PATCH 03/62] Factor out reasoning about strings in own strategy --- .../ilkd/key/strategy/JavaCardDLStrategy.java | 95 ---------- .../key/strategy/ModularJavaDLStrategy.java | 9 +- .../uka/ilkd/key/strategy/StringStrategy.java | 176 ++++++++++++++++++ 3 files changed, 181 insertions(+), 99 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 223f02aa14..222fd10286 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -5,16 +5,12 @@ import java.util.concurrent.atomic.AtomicLong; -import de.uka.ilkd.key.ldt.BooleanLDT; -import de.uka.ilkd.key.ldt.CharListLDT; import de.uka.ilkd.key.ldt.HeapLDT; import de.uka.ilkd.key.ldt.IntegerLDT; import de.uka.ilkd.key.ldt.LocSetLDT; -import de.uka.ilkd.key.ldt.SeqLDT; import de.uka.ilkd.key.logic.op.Equality; import de.uka.ilkd.key.logic.op.Junctor; import de.uka.ilkd.key.logic.op.Quantifier; -import de.uka.ilkd.key.logic.op.SortDependingFunction; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.UseDependencyContractRule; @@ -47,7 +43,6 @@ import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; import org.key_project.prover.strategy.costbased.termfeature.IsNonRigidTermFeature; import org.key_project.prover.strategy.costbased.termfeature.OperatorClassTF; -import org.key_project.prover.strategy.costbased.termfeature.TermFeature; import org.jspecify.annotations.NonNull; @@ -280,8 +275,6 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "update_join", -4600); bindRuleSet(d, "update_apply", -4500); - setUpStringNormalisation(d); - setupSplitting(d); bindRuleSet(d, "test_gen", inftyConst()); @@ -558,94 +551,6 @@ private void setupSelectSimplification(final RuleSetDispatchFeature d) { add(isSelectSkolemConstantTerm("auxiliarySK"), longConst(-500))); } - private void setUpStringNormalisation(RuleSetDispatchFeature d) { - - // translates an integer into its string representation - bindRuleSet(d, "integerToString", -10000); - - // do not convert char to int when inside a string function - // feature used to recognize if one is inside a string literal - final SeqLDT seqLDT = getServices().getTypeConverter().getSeqLDT(); - final CharListLDT charListLDT = getServices().getTypeConverter().getCharListLDT(); - final BooleanLDT booleanLDT = getServices().getTypeConverter().getBooleanLDT(); - - - final TermFeature keepChar = - or(op(seqLDT.getSeqSingleton()), or(op(charListLDT.getClIndexOfChar()), - or(op(charListLDT.getClReplace()), op(charListLDT.getClLastIndexOfChar())))); - - bindRuleSet(d, "charLiteral_to_intLiteral", - ifZero(isBelow(keepChar), inftyConst(), longConst(-100))); - - // establish normalform - - // tf below only for test - final TermFeature anyLiteral = or(tf.charLiteral, - or(tf.literal, op(booleanLDT.getFalseConst()), op(booleanLDT.getTrueConst()))); - - final TermFeature seqLiteral = rec(anyLiteral, or(op(seqLDT.getSeqConcat()), - or(op(seqLDT.getSeqSingleton()), or(anyLiteral, inftyTermConst())))); - - Feature belowModOpPenality = ifZero(isBelow(ff.modalOperator), longConst(500)); - - bindRuleSet(d, "defOpsSeqEquality", - add(NonDuplicateAppModPositionFeature.INSTANCE, - ifZero(add(applyTF("left", seqLiteral), applyTF("right", seqLiteral)), - longConst(1000), inftyConst()), - belowModOpPenality)); - - bindRuleSet(d, "defOpsConcat", - add(NonDuplicateAppModPositionFeature.INSTANCE, - ifZero( - or(applyTF("leftStr", not(seqLiteral)), applyTF("rightStr", not(seqLiteral))), - longConst(1000) - // concat is often introduced for construction purposes, - // we do not want to use its definition right at the - // beginning - ), belowModOpPenality)); - - bindRuleSet(d, "stringsSimplify", longConst(-5000)); - - final TermFeature charOrIntLiteral = or(tf.charLiteral, tf.literal, - or(add(OperatorClassTF.create(SortDependingFunction.class), // XXX: - // was CastFunctionSymbol.class - sub(tf.literal)), inftyTermConst())); - - bindRuleSet(d, "defOpsReplaceInline", - ifZero(add(applyTF("str", seqLiteral), applyTF("searchChar", charOrIntLiteral), - applyTF("replChar", charOrIntLiteral)), longConst(-2500), inftyConst())); - - bindRuleSet(d, "defOpsReplace", add(NonDuplicateAppModPositionFeature.INSTANCE, - ifZero(or(applyTF("str", not(seqLiteral)), applyTF("searchChar", not(charOrIntLiteral)), - applyTF("replChar", not(charOrIntLiteral))), longConst(500), inftyConst()), - belowModOpPenality)); - - bindRuleSet(d, "stringsReduceSubstring", - add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(100))); - - bindRuleSet(d, "defOpsStartsEndsWith", longConst(250)); - - bindRuleSet(d, "stringsConcatNotBothLiterals", - ifZero(MatchedAssumesFeature.INSTANCE, ifZero( - add(applyTF(instOf("leftStr"), seqLiteral), - applyTF(instOf("rightStr"), seqLiteral)), - inftyConst()), inftyConst())); - - bindRuleSet(d, "stringsReduceConcat", longConst(100)); - - bindRuleSet(d, "stringsReduceOrMoveOutsideConcat", - ifZero(NonDuplicateAppModPositionFeature.INSTANCE, longConst(800), inftyConst())); - - bindRuleSet(d, "stringsMoveReplaceInside", - ifZero(NonDuplicateAppModPositionFeature.INSTANCE, longConst(400), inftyConst())); - - - bindRuleSet(d, "stringsExpandDefNormalOp", longConst(500)); - - bindRuleSet(d, "stringsContainsDefInline", SumFeature - .createSum(EqNonDuplicateAppFeature.INSTANCE, longConst(1000))); - } - private void setupReplaceKnown(RuleSetDispatchFeature d) { final Feature commonF = add(ifZero(MatchedAssumesFeature.INSTANCE, DiffFindAndIfFeature.INSTANCE), diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 8dc41296b1..1c62742761 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -25,11 +25,12 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final List strategies = new ArrayList<>(); private final StrategyProperties strategyProperties; - public ModularJavaDLStrategy(Proof proof, StrategyProperties strategyProperties) { + public ModularJavaDLStrategy(Proof proof, StrategyProperties properties) { super(proof); - strategies.add(new JavaCardDLStrategy(proof, strategyProperties)); - strategies.add(new IntegerStrategy(proof, strategyProperties)); - this.strategyProperties = (StrategyProperties) strategyProperties.clone(); + strategies.add(new IntegerStrategy(proof, properties)); + strategies.add(new StringStrategy(proof, properties)); + strategies.add(new JavaCardDLStrategy(proof, properties)); + this.strategyProperties = (StrategyProperties) properties.clone(); } @Override diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java new file mode 100644 index 0000000000..2d2297efc0 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -0,0 +1,176 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.ldt.BooleanLDT; +import de.uka.ilkd.key.ldt.CharListLDT; +import de.uka.ilkd.key.ldt.SeqLDT; +import de.uka.ilkd.key.logic.op.SortDependingFunction; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.feature.*; +import de.uka.ilkd.key.strategy.termProjection.*; + +import org.key_project.logic.Name; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.TopRuleAppCost; +import org.key_project.prover.strategy.costbased.feature.Feature; +import org.key_project.prover.strategy.costbased.feature.SumFeature; +import org.key_project.prover.strategy.costbased.termfeature.OperatorClassTF; +import org.key_project.prover.strategy.costbased.termfeature.TermFeature; + +import org.jspecify.annotations.NonNull; + +public class StringStrategy extends AbstractFeatureStrategy { + public static final Name NAME = new Name("String Strategy"); + + /// The features defining the three phases: cost computation, approval, + /// additionalInstanceCreationAndEvaluation + private final RuleSetDispatchFeature costComputationDispatcher; + + /// Useful [TermFeature] collections + private final ArithTermFeatures tf; + private final FormulaTermFeatures ff; + + private final boolean stopAtFirstNonCloseableGoal; + + public StringStrategy(Proof proof, StrategyProperties strategyProperties) { + super(proof); + this.tf = new ArithTermFeatures(proof.getServices().getTypeConverter().getIntegerLDT()); + this.ff = new FormulaTermFeatures(this.tf); + + costComputationDispatcher = setupCostComputationF(); + + stopAtFirstNonCloseableGoal = + strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) + .equals(StrategyProperties.STOPMODE_NONCLOSE); + } + + private RuleSetDispatchFeature setupCostComputationF() { + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + setUpStringNormalisation(d); + return d; + } + + private void setUpStringNormalisation(RuleSetDispatchFeature d) { + // translates an integer into its string representation + bindRuleSet(d, "integerToString", -10000); + + // do not convert char to int when inside a string function + // feature used to recognize if one is inside a string literal + final SeqLDT seqLDT = getServices().getTypeConverter().getSeqLDT(); + final CharListLDT charListLDT = getServices().getTypeConverter().getCharListLDT(); + final BooleanLDT booleanLDT = getServices().getTypeConverter().getBooleanLDT(); + + + final TermFeature keepChar = + or(op(seqLDT.getSeqSingleton()), or(op(charListLDT.getClIndexOfChar()), + or(op(charListLDT.getClReplace()), op(charListLDT.getClLastIndexOfChar())))); + + bindRuleSet(d, "charLiteral_to_intLiteral", + ifZero(isBelow(keepChar), inftyConst(), longConst(-100))); + + // establish normalform + + // tf below only for test + final TermFeature anyLiteral = or(tf.charLiteral, + or(tf.literal, op(booleanLDT.getFalseConst()), op(booleanLDT.getTrueConst()))); + + final TermFeature seqLiteral = rec(anyLiteral, or(op(seqLDT.getSeqConcat()), + or(op(seqLDT.getSeqSingleton()), or(anyLiteral, inftyTermConst())))); + + Feature belowModOpPenality = ifZero(isBelow(ff.modalOperator), longConst(500)); + + bindRuleSet(d, "defOpsSeqEquality", + add(NonDuplicateAppModPositionFeature.INSTANCE, + ifZero(add(applyTF("left", seqLiteral), applyTF("right", seqLiteral)), + longConst(1000), inftyConst()), + belowModOpPenality)); + + bindRuleSet(d, "defOpsConcat", + add(NonDuplicateAppModPositionFeature.INSTANCE, + ifZero( + or(applyTF("leftStr", not(seqLiteral)), applyTF("rightStr", not(seqLiteral))), + longConst(1000) + // concat is often introduced for construction purposes, + // we do not want to use its definition right at the + // beginning + ), belowModOpPenality)); + + bindRuleSet(d, "stringsSimplify", longConst(-5000)); + + final TermFeature charOrIntLiteral = or(tf.charLiteral, tf.literal, + or(add(OperatorClassTF.create(SortDependingFunction.class), // XXX: + // was CastFunctionSymbol.class + sub(tf.literal)), inftyTermConst())); + + bindRuleSet(d, "defOpsReplaceInline", + ifZero(add(applyTF("str", seqLiteral), applyTF("searchChar", charOrIntLiteral), + applyTF("replChar", charOrIntLiteral)), longConst(-2500), inftyConst())); + + bindRuleSet(d, "defOpsReplace", add(NonDuplicateAppModPositionFeature.INSTANCE, + ifZero(or(applyTF("str", not(seqLiteral)), applyTF("searchChar", not(charOrIntLiteral)), + applyTF("replChar", not(charOrIntLiteral))), longConst(500), inftyConst()), + belowModOpPenality)); + + bindRuleSet(d, "stringsReduceSubstring", + add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(100))); + + bindRuleSet(d, "defOpsStartsEndsWith", longConst(250)); + + bindRuleSet(d, "stringsConcatNotBothLiterals", + ifZero(MatchedAssumesFeature.INSTANCE, ifZero( + add(applyTF(instOf("leftStr"), seqLiteral), + applyTF(instOf("rightStr"), seqLiteral)), + inftyConst()), inftyConst())); + + bindRuleSet(d, "stringsReduceConcat", longConst(100)); + + bindRuleSet(d, "stringsReduceOrMoveOutsideConcat", + ifZero(NonDuplicateAppModPositionFeature.INSTANCE, longConst(800), inftyConst())); + + bindRuleSet(d, "stringsMoveReplaceInside", + ifZero(NonDuplicateAppModPositionFeature.INSTANCE, longConst(400), inftyConst())); + + + bindRuleSet(d, "stringsExpandDefNormalOp", longConst(500)); + + bindRuleSet(d, "stringsContainsDefInline", SumFeature + .createSum(EqNonDuplicateAppFeature.INSTANCE, longConst(1000))); + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return stopAtFirstNonCloseableGoal; + } + + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return !(NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, + new MutableState()) == TopRuleAppCost.INSTANCE); + + } + + @Override + protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return longConst(0).computeCost(app, pio, goal, mState); + } + + @Override + public Name name() { + return NAME; + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, Goal goal, MutableState mState) { + return this.costComputationDispatcher.computeCost(app, pos, goal, mState); + } +} From 66a75591643aaf8d0931af33b5612b6bbf85a94b Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 12:34:15 +0200 Subject: [PATCH 04/62] Moves FormulaTag manager to ncore (start of generalizing the indexing structures) --- .../main/java/de/uka/ilkd/key/proof/Goal.java | 6 +- .../label/OriginTermLabelRefactoring.java | 2 +- .../key/strategy/AssumesInstantiator.java | 6 +- .../key/strategy/BuiltInRuleAppContainer.java | 2 +- .../key/strategy/FindTacletAppContainer.java | 15 +- .../FocussedRuleApplicationManager.java | 2 +- .../prover/indexing}/FormulaTag.java | 6 +- .../prover/indexing}/FormulaTagManager.java | 142 ++++++++++-------- .../key_project/prover/proof/ProofGoal.java | 6 + .../prover/sequent/SequentChangeInfo.java | 3 +- 10 files changed, 103 insertions(+), 87 deletions(-) rename {key.core/src/main/java/de/uka/ilkd/key/proof => key.ncore.calculus/src/main/java/org/key_project/prover/indexing}/FormulaTag.java (85%) rename {key.core/src/main/java/de/uka/ilkd/key/proof => key.ncore.calculus/src/main/java/org/key_project/prover/indexing}/FormulaTagManager.java (61%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index 29c7374827..94fa280399 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -31,6 +31,7 @@ import org.key_project.logic.PosInTerm; import org.key_project.logic.op.Function; +import org.key_project.prover.indexing.FormulaTagManager; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.proof.rulefilter.TacletFilter; import org.key_project.prover.rules.RuleAbortException; @@ -237,10 +238,9 @@ public void removeGoalListener(GoalListener l) { * creation the necessary information is passed to the listener as parameters and not through an * event object. */ - private void fireSequentChanged( - SequentChangeInfo sci) { + private void fireSequentChanged(SequentChangeInfo sci) { var time = System.nanoTime(); - getFormulaTagManager().sequentChanged(this, sci); + getFormulaTagManager().sequentChanged(sci, getTime()); var time1 = System.nanoTime(); PERF_UPDATE_TAG_MANAGER.getAndAdd(time1 - time); ruleAppIndex.sequentChanged(sci); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/label/OriginTermLabelRefactoring.java b/key.core/src/main/java/de/uka/ilkd/key/rule/label/OriginTermLabelRefactoring.java index 5b8d89dd79..6c32d39c9c 100755 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/label/OriginTermLabelRefactoring.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/label/OriginTermLabelRefactoring.java @@ -15,12 +15,12 @@ import de.uka.ilkd.key.logic.label.OriginTermLabelFactory; import de.uka.ilkd.key.logic.label.TermLabel; import de.uka.ilkd.key.logic.label.TermLabelState; -import de.uka.ilkd.key.proof.FormulaTag; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.rule.Taclet; import org.key_project.logic.Name; +import org.key_project.prover.indexing.FormulaTag; import org.key_project.prover.rules.Rule; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.util.collection.ImmutableArray; diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/AssumesInstantiator.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/AssumesInstantiator.java index f437c587ba..ade18d41eb 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/AssumesInstantiator.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/AssumesInstantiator.java @@ -6,8 +6,6 @@ import java.util.Iterator; import de.uka.ilkd.key.java.Services; -import de.uka.ilkd.key.proof.FormulaTag; -import de.uka.ilkd.key.proof.FormulaTagManager; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.rule.MatchConditions; import de.uka.ilkd.key.rule.NoPosTacletApp; @@ -16,6 +14,7 @@ import de.uka.ilkd.key.util.Debug; import org.key_project.logic.PosInTerm; +import org.key_project.prover.indexing.FormulaTagManager; import org.key_project.prover.rules.instantiation.AssumesFormulaInstSeq; import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; import org.key_project.prover.rules.instantiation.AssumesMatchResult; @@ -169,8 +168,7 @@ private boolean isNewFormulaDirect(AssumesFormulaInstSeq p_ifInstantiation) { final FormulaTagManager tagManager = goal.getFormulaTagManager(); - final FormulaTag tag = tagManager.getTagForPos(pio); - final long formulaAge = tagManager.getAgeForTag(tag); + final long formulaAge = tagManager.getAgeForPos(pio); // The strict relation can be used, because when applying a rule the // age of a goal is increased before the actual modification of the diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/BuiltInRuleAppContainer.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/BuiltInRuleAppContainer.java index e7af8fd365..cbcb861dd3 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/BuiltInRuleAppContainer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/BuiltInRuleAppContainer.java @@ -3,11 +3,11 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import de.uka.ilkd.key.proof.FormulaTag; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.rule.IBuiltInRuleApp; +import org.key_project.prover.indexing.FormulaTag; import org.key_project.prover.rules.RuleApp; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.RuleAppCost; diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FindTacletAppContainer.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FindTacletAppContainer.java index f27afbd8d1..e9bf3c07b6 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FindTacletAppContainer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FindTacletAppContainer.java @@ -5,13 +5,12 @@ import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.op.UpdateApplication; -import de.uka.ilkd.key.proof.FormulaTag; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.rule.NoPosTacletApp; -import de.uka.ilkd.key.util.Debug; import org.key_project.logic.op.Modality; import org.key_project.logic.op.Operator; +import org.key_project.prover.indexing.FormulaTag; import org.key_project.prover.sequent.FormulaChangeInfo; import org.key_project.prover.sequent.PIOPathIterator; import org.key_project.prover.sequent.PosInOccurrence; @@ -19,6 +18,8 @@ import org.key_project.prover.strategy.costbased.RuleAppCost; import org.key_project.util.collection.ImmutableList; +import org.jspecify.annotations.NonNull; + import static de.uka.ilkd.key.logic.equality.IrrelevantTermLabelsProperty.IRRELEVANT_TERM_LABELS_PROPERTY; /** @@ -49,12 +50,10 @@ public class FindTacletAppContainer extends TacletAppContainer { long age) { super(app, cost, age); applicationPosition = pio; - positionTag = goal.getFormulaTagManager().getTagForPos(pio.topLevel()); - if (positionTag == null) { - // faster than assertFalse - Debug.fail("Formula " + pio + " does not exist"); - } + final FormulaTag posTag = goal.getFormulaTagManager().getTagForPos(pio.topLevel()); + assert posTag != null : "No formula tag found for " + pio; + positionTag = posTag; } @@ -75,7 +74,7 @@ protected boolean isStillApplicable(Goal p_goal) { * altered since the creation of this object or if a preceding update has changed */ private boolean subformulaOrPreceedingUpdateHasChanged(Goal goal) { - ImmutableList infoList = + ImmutableList<@NonNull FormulaChangeInfo> infoList = goal.getFormulaTagManager().getModifications(positionTag); while (!infoList.isEmpty()) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FocussedRuleApplicationManager.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FocussedRuleApplicationManager.java index cca113d178..5ab8202f1a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FocussedRuleApplicationManager.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FocussedRuleApplicationManager.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import de.uka.ilkd.key.proof.FormulaTag; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.strategy.feature.NonDuplicateAppModPositionFeature; +import org.key_project.prover.indexing.FormulaTag; import org.key_project.prover.rules.RuleApp; import org.key_project.prover.sequent.PIOPathIterator; import org.key_project.prover.sequent.PosInOccurrence; diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/FormulaTag.java b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTag.java similarity index 85% rename from key.core/src/main/java/de/uka/ilkd/key/proof/FormulaTag.java rename to key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTag.java index 40bbda5bae..e20237b982 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/FormulaTag.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTag.java @@ -1,19 +1,19 @@ /* This file is part of KeY - https://key-project.org * KeY is licensed under the GNU General Public License Version 2 * SPDX-License-Identifier: GPL-2.0-only */ -package de.uka.ilkd.key.proof; +package org.key_project.prover.indexing; /** * Class whose instances represent tags to identify the formulas of sequents persistently, i.e. a * tag does not become invalid when a formula is modified by a rule application. Tags are managed by * the class FormulaTagManager for each Node */ -public final class FormulaTag { +final public class FormulaTag { static int counter = 0; final int i; - FormulaTag() { + public FormulaTag() { i = counter++; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/FormulaTagManager.java b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java similarity index 61% rename from key.core/src/main/java/de/uka/ilkd/key/proof/FormulaTagManager.java rename to key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java index 645c893378..89f65a5274 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/FormulaTagManager.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java @@ -1,25 +1,27 @@ /* This file is part of KeY - https://key-project.org * KeY is licensed under the GNU General Public License Version 2 * SPDX-License-Identifier: GPL-2.0-only */ -package de.uka.ilkd.key.proof; +package org.key_project.prover.indexing; import java.util.HashMap; import java.util.LinkedHashMap; -import de.uka.ilkd.key.util.Debug; - import org.key_project.logic.PosInTerm; +import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.sequent.*; import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSLList; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + /** * Class to manage the tags of the formulas of a sequent (node). Instances of this class are stored * by instances of the Goal class, and are not immutable */ -public class FormulaTagManager { +public final class FormulaTagManager { - /** Maps for the assignment of tags to formulas and vice versa */ + // Maps for the assignment of tags to formulas and vice versa /** Key: FormulaTag Value: FormulaInfo */ private final HashMap tagToFormulaInfo; @@ -30,7 +32,7 @@ public class FormulaTagManager { /** * Create a new manager that is initialised with the formulas of the given sequent */ - FormulaTagManager(Goal p_goal) { + public FormulaTagManager(ProofGoal p_goal) { tagToFormulaInfo = new LinkedHashMap<>(); pioToTag = new LinkedHashMap<>(); createNewTags(p_goal); @@ -45,7 +47,7 @@ private FormulaTagManager(HashMap p_tagToPIO, /** * @return the tag of the formula at the given position */ - public FormulaTag getTagForPos(PosInOccurrence p_pio) { + public @Nullable FormulaTag getTagForPos(PosInOccurrence p_pio) { return pioToTag.get(p_pio); } @@ -54,7 +56,7 @@ public FormulaTag getTagForPos(PosInOccurrence p_pio) { * returned PosInOccurrence can be obsolete and refer to a previous node. * If no formula is assigned to the given tag, null is returned */ - public PosInOccurrence getPosForTag(FormulaTag p_tag) { + public @Nullable PosInOccurrence getPosForTag(FormulaTag p_tag) { final FormulaInfo info = getFormulaInfo(p_tag); if (info == null) { return null; @@ -76,45 +78,43 @@ public long getAgeForTag(FormulaTag p_tag) { } /** + * The provided tag must be actively managed by the {@link FormulaTagManager} + * * @return All modifications that were applied to the formula with the given tag since the * creation of the tag, starting with the most recent one */ - public ImmutableList getModifications( - FormulaTag p_tag) { - return getFormulaInfo(p_tag).modifications; + public ImmutableList<@NonNull FormulaChangeInfo> getModifications(FormulaTag p_tag) { + final FormulaInfo formulaInfo = getFormulaInfo(p_tag); + assert formulaInfo != null + : "@AssumeAssertion(nullness): Method should only be called for valid/existing tags"; + return formulaInfo.modifications; } + public void sequentChanged(SequentChangeInfo sci, long newAge) { + removeTags(sci, true); + removeTags(sci, false); - public void sequentChanged(Goal source, - SequentChangeInfo sci) { - assert source != null; - removeTags(sci, true, source); - removeTags(sci, false, source); + updateTags(sci, true, newAge); + updateTags(sci, false, newAge); - updateTags(sci, true, source); - updateTags(sci, false, source); - - addTags(sci, true, source); - addTags(sci, false, source); + addTags(sci, true, newAge); + addTags(sci, false, newAge); } - private void updateTags(SequentChangeInfo sci, - boolean p_antec, Goal p_goal) { + private void updateTags(SequentChangeInfo sci, boolean p_antec, long newAge) { for (var formulaChangeInfo : sci.modifiedFormulas(p_antec)) { - updateTag(formulaChangeInfo, p_goal); + updateTag(formulaChangeInfo, newAge); } } - private void addTags(SequentChangeInfo sci, - boolean p_antec, Goal p_goal) { + private void addTags(SequentChangeInfo sci, boolean p_antec, long age) { for (SequentFormula sf : sci.addedFormulas(p_antec)) { final PosInOccurrence pio = new PosInOccurrence(sf, PosInTerm.getTopLevel(), p_antec); - createNewTag(pio, p_goal); + createNewTag(pio, age); } } - private void removeTags(SequentChangeInfo sci, - boolean p_antec, Goal p_goal) { + private void removeTags(SequentChangeInfo sci, boolean p_antec) { for (SequentFormula sf : sci.removedFormulas(p_antec)) { final PosInOccurrence pio = new PosInOccurrence(sf, PosInTerm.getTopLevel(), p_antec); removeTag(pio); @@ -138,25 +138,26 @@ public FormulaTagManager copy() { * * @param p_goal The sequent */ - private void createNewTags(Goal p_goal) { - createNewTags(p_goal, false); - createNewTags(p_goal, true); + private void createNewTags(ProofGoal p_goal) { + final Sequent seq = p_goal.sequent(); + final long age = p_goal.getTime(); + createNewTags(seq.succedent(), age, false); + createNewTags(seq.antecedent(), age, true); } /** * Create new tags for all formulas of a semisequent * - * @param p_goal The sequent that contains the semisequent - * @param p_antec true iff the formulas of the antecedent should be added + * @param semisequent the {@link Semisequent} for which to create the tags + * @param newAge the long indicating the age of the {@link ProofGoal} to which the semisequent + * belongs + * @param p_antec true iff the semisequent is an antecedent */ - private void createNewTags(Goal p_goal, boolean p_antec) { - final Sequent seq = p_goal.sequent(); - final Semisequent ss = p_antec ? seq.antecedent() : seq.succedent(); - - for (SequentFormula s : ss) { + private void createNewTags(Semisequent semisequent, long newAge, boolean p_antec) { + for (SequentFormula s : semisequent) { final PosInOccurrence pio = new PosInOccurrence(s, PosInTerm.getTopLevel(), p_antec); - createNewTag(pio, p_goal); + createNewTag(pio, newAge); } } @@ -165,9 +166,9 @@ private void createNewTags(Goal p_goal, boolean p_antec) { * * @param p_pio The formula for which a new tag is supposed to be created */ - private void createNewTag(PosInOccurrence p_pio, Goal p_goal) { + private void createNewTag(PosInOccurrence p_pio, long age) { final FormulaTag tag = new FormulaTag(); - tagToFormulaInfo.put(tag, new FormulaInfo(p_pio, p_goal.getTime())); + tagToFormulaInfo.put(tag, new FormulaInfo(p_pio, age)); pioToTag.put(p_pio, tag); } @@ -177,19 +178,23 @@ private void createNewTag(PosInOccurrence p_pio, Goal p_goal) { private void removeTag(PosInOccurrence p_pio) { final FormulaTag tag = getTagForPos(p_pio); - Debug.assertFalse(tag == null, "Tried to remove a tag that does not exist"); + assert tag != null + : "@AssumeAssertion(nullness): Tried to remove a tag that does not exist"; tagToFormulaInfo.remove(tag); putInQueryCache(tag, null); pioToTag.remove(p_pio); } - private void updateTag(FormulaChangeInfo p_info, Goal p_goal) { - final PosInOccurrence oldPIO = - p_info.positionOfModification().topLevel(); + private void updateTag(FormulaChangeInfo p_info, long newAge) { + final PosInOccurrence oldPIO = p_info.positionOfModification().topLevel(); final FormulaTag tag = getTagForPos(oldPIO); + assert tag != null + : "@AssumeAssertion(nullness): Tried to update a tag that does not exist"; final FormulaInfo oldInfo = getFormulaInfo(tag); - final FormulaInfo newInfo = oldInfo.addModification(p_info, p_goal.getTime()); + assert oldInfo != null + : "@AssumeAssertion(nullness): Tried to update a tag with no previous information"; + final FormulaInfo newInfo = oldInfo.addModification(p_info, newAge); tagToFormulaInfo.put(tag, newInfo); putInQueryCache(tag, newInfo); @@ -200,23 +205,35 @@ private void updateTag(FormulaChangeInfo p_info, Goal p_goal) { //////////////////////////////////////////////////////////////////////////// // Simple cache for getFormulaInfo - private FormulaTag lastTagQueried = null; - private FormulaInfo lastQueryResult = null; + private @Nullable FormulaTag lastTagQueried = null; + private @Nullable FormulaInfo lastQueryResult = null; - private void putInQueryCache(FormulaTag p_tag, FormulaInfo p_info) { + private void putInQueryCache(FormulaTag p_tag, @Nullable FormulaInfo p_info) { lastTagQueried = p_tag; lastQueryResult = p_info; } //////////////////////////////////////////////////////////////////////////// - private FormulaInfo getFormulaInfo(FormulaTag p_tag) { + private @Nullable FormulaInfo getFormulaInfo(FormulaTag p_tag) { if (lastTagQueried != p_tag) { putInQueryCache(p_tag, tagToFormulaInfo.get(p_tag)); } return lastQueryResult; } + /// retrieves the age for the given position + /// @param pio the [PosInOccurrence] of the formula whose age is queries + /// @return the age for the given position + /// @throws IllegalStateException if pos in occurrence does not describe a known formula + public long getAgeForPos(PosInOccurrence pio) { + final FormulaTag tag = getTagForPos(pio); + if (tag == null) { + throw new IllegalStateException("Formula tag for " + pio + " not found"); + } + return getAgeForTag(tag); + } + /** * Class that holds information about a formula, namely the current position @@ -248,27 +265,22 @@ public String toString() { */ public final long age; - public FormulaInfo(PosInOccurrence p_pio, long p_age) { - this(p_pio, ImmutableSLList.nil(), p_age); + public FormulaInfo(PosInOccurrence pio, long age) { + this(pio, ImmutableSLList.nil(), age); } - private FormulaInfo(PosInOccurrence p_pio, - ImmutableList p_modifications, - long p_age) { - pio = p_pio; - modifications = p_modifications; - age = p_age; + private FormulaInfo(PosInOccurrence pio, ImmutableList modifications, + long age) { + this.pio = pio; + this.modifications = modifications; + this.age = age; } - public FormulaInfo addModification( - FormulaChangeInfo p_info, - long p_age) { + public FormulaInfo addModification(FormulaChangeInfo p_info, long p_age) { final PosInOccurrence newPIO = new PosInOccurrence(p_info.newFormula(), PosInTerm.getTopLevel(), pio.isInAntec()); - return new FormulaInfo(newPIO, - modifications.prepend(p_info), - p_age); + return new FormulaInfo(newPIO, modifications.prepend(p_info), p_age); } } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/proof/ProofGoal.java b/key.ncore.calculus/src/main/java/org/key_project/prover/proof/ProofGoal.java index 211521256d..3098da42ba 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/proof/ProofGoal.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/proof/ProofGoal.java @@ -39,4 +39,10 @@ public interface ProofGoal> { /// @return the RuleApplicationManager selecting the next rule /// application to be applied on this goal RuleApplicationManager getRuleAppManager(); + + /// returns the current time of this goal + /// the only requirement is that a goal that is a successor of this goal returns + /// a larger number + /// @return long with current time of goal + long getTime(); } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/SequentChangeInfo.java b/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/SequentChangeInfo.java index ab424a948a..4019dd8d5b 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/SequentChangeInfo.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/SequentChangeInfo.java @@ -148,7 +148,8 @@ public ImmutableList removedFormulas(boolean inAntecedent) { /// @param inAntecedent a boolean used to select one of the two semisequents of a sequent /// (true means antecedent; false means succedent) /// @return list of formulas modified within the selected semisequent - public ImmutableList modifiedFormulas(boolean inAntecedent) { + public @NonNull ImmutableList<@NonNull FormulaChangeInfo> modifiedFormulas( + boolean inAntecedent) { return inAntecedent ? antecedent.modifiedFormulas() : succedent.modifiedFormulas(); } From bc6a8550da9c702801cad7af40cea2334d146f65 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 13:48:12 +0200 Subject: [PATCH 05/62] Move RuleIndex to ncore --- .../key/proof/MultiThreadedTacletIndex.java | 8 +- .../java/de/uka/ilkd/key/proof/RuleIndex.java | 144 ++++++++++++++++++ .../key/proof/SingleThreadedTacletIndex.java | 3 +- .../de/uka/ilkd/key/proof/TacletIndex.java | 38 +++-- 4 files changed, 175 insertions(+), 18 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java index 5d8e79a9d6..5abc180bfc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java @@ -13,6 +13,7 @@ import de.uka.ilkd.key.rule.NoPosTacletApp; import de.uka.ilkd.key.rule.Taclet; +import org.key_project.logic.LogicServices; import org.key_project.prover.proof.rulefilter.RuleFilter; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.util.collection.ImmutableList; @@ -70,8 +71,7 @@ public TacletIndex copy() { */ @Override protected ImmutableList matchTaclets(ImmutableList tacletApps, - RuleFilter p_filter, PosInOccurrence pos, - Services services) { + RuleFilter p_filter, PosInOccurrence pos, LogicServices services) { ImmutableList result = ImmutableSLList.nil(); if (tacletApps == null) { @@ -124,7 +124,7 @@ static class TacletSetMatchTask implements Callable> { private final NoPosTacletApp[] toMatch; private final int lower; private final int upper; - private final Services services; + private final LogicServices services; private final PosInOccurrence pos; private final RuleFilter ruleFilter; @@ -142,7 +142,7 @@ static class TacletSetMatchTask implements Callable> { */ public TacletSetMatchTask(NoPosTacletApp[] toMatch, int lower, int upper, PosInOccurrence pos, RuleFilter ruleFilter, - Services services) { + LogicServices services) { this.toMatch = toMatch; this.lower = lower; this.upper = upper; diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java new file mode 100644 index 0000000000..cb2da25f2b --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java @@ -0,0 +1,144 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.proof; + +import java.util.Set; + +import org.key_project.logic.LogicServices; +import org.key_project.logic.Name; +import org.key_project.prover.proof.rulefilter.RuleFilter; +import org.key_project.prover.rules.Rule; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.util.collection.ImmutableList; + +import org.jspecify.annotations.Nullable; + +public interface RuleIndex extends Cloneable { + + /** + * adds a set of NoPosTacletApp to this index + * + * @param tacletAppList the NoPosTacletApps to be added + */ + void addTaclets(Iterable tacletAppList); + + /** + * adds a new Taclet with instantiation information to this index. If rule instance is not known + * rule is not added + * + * @param taclet the Taclet and its instantiation info to be added + */ + void add(Rule taclet); + + /** + * adds a new Taclet with instantiation information to this index. If rule instance is not known + * rule is not added + * + * @param tacletApplication the Taclet and its instantiation info to be added + */ + void add(Application tacletApplication); + + /** + * removes a Taclet with the given instantiation information from this index. + * + * @param tacletApplication the Taclet and its instantiation info to be removed + */ + void remove(Application tacletApplication); + + /** + * removes the given NoPosTacletApps from this index + * + * @param tacletAppList the NoPosTacletApps to be removed + */ + void removeTaclets(Iterable tacletAppList); + + /** + * copies the index + */ + TacletIndex copy(); + + /** + * clones the index + */ + Object clone(); + + Set allNoPosTacletApps(); + + /** + * get all Taclets for the antecedent. + * + * @param pos the PosOfOccurrence describing the formula for which to look for top level taclets + * @param filter Only return taclets the filter selects + * @param services the Services object encapsulating information about the java datastructures + * like (static)types etc. + * @return IList containing all applicable rules and the corresponding + * instantiations to get the rule fit. + */ + ImmutableList getAntecedentTaclet(PosInOccurrence pos, RuleFilter filter, + LogicServices services); + + /** + * get all Taclets for the succedent. + * + * @param pos the PosOfOccurrence describing the formula for which to look for top level taclets + * @param filter Only return taclets the filter selects + * @param services the Services object encapsulating information about the java datastructures + * like (static)types etc. + * @return IList containing all applicable rules and the corresponding + * instantiations to get the rule fit. + */ + ImmutableList getSuccedentTaclet( + PosInOccurrence pos, RuleFilter filter, + LogicServices services); + + /** + * get all Rewrite-Taclets. + * + * @param filter Only return taclets the filter selects + * @param services the Services object encapsulating information about the java datastructures + * like (static)types etc. + * @return IList containing all applicable rules and the corresponding + * instantiations to get the rule fit. + */ + ImmutableList getRewriteTaclet(PosInOccurrence pos, RuleFilter filter, + LogicServices services); + + /** + * get all Taclets having no find expression. + * + * @param filter Only return taclets the filter selects + * @param services the Services object encapsulating information about the java datastructures + * like (static)types etc. + * @return IList containing all applicable rules and an empty part for the + * instantiations because no instantiations are necessary. + */ + ImmutableList getNoFindTaclet(RuleFilter filter, LogicServices services); + + /** + * returns a NoPosTacletApp whose Taclet has a name that equals the given name. If more Taclets + * have the same name an arbitrary Taclet with that name is returned. + * + * @param name the name to lookup + * @return the found NoPosTacletApp or null if no matching Taclet is there + */ + Application lookup(Name name); + + /** + * returns a NoPosTacletApp whose Taclet has a name that equals the given name. If more Taclets + * have the same name an arbitrary Taclet with that name is returned. + * + * @param name the name to lookup + * @return the found NoPosTacletApp or null if no matching Taclet is there + */ + @Nullable + Application lookup(String name); + + /** + * returns an unmodifiable set with all partial instantiated no pos taclet apps + * + * @return set with all partial instantiated NoPosTacletApps + */ + Set getPartialInstantiatedApps(); +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java index 8573001629..9087d54d5c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java @@ -10,6 +10,7 @@ import de.uka.ilkd.key.rule.NoPosTacletApp; import de.uka.ilkd.key.rule.Taclet; +import org.key_project.logic.LogicServices; import org.key_project.prover.proof.rulefilter.RuleFilter; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.util.collection.ImmutableList; @@ -63,7 +64,7 @@ public TacletIndex copy() { */ @Override protected ImmutableList matchTaclets(ImmutableList tacletApps, - RuleFilter p_filter, PosInOccurrence pos, Services services) { + RuleFilter p_filter, PosInOccurrence pos, LogicServices services) { ImmutableList result = ImmutableSLList.nil(); if (tacletApps == null) { return result; diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java index 726487a0d0..f8bbe11ea8 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java @@ -16,6 +16,7 @@ import de.uka.ilkd.key.strategy.quantifierHeuristics.Metavariable; import de.uka.ilkd.key.util.Debug; +import org.key_project.logic.LogicServices; import org.key_project.logic.Name; import org.key_project.logic.op.Operator; import org.key_project.logic.op.sv.OperatorSV; @@ -35,7 +36,7 @@ * added because the Taclets allow to introduce new rules during runtime. It offers selective get * methods for different kinds of rules. */ -public abstract class TacletIndex { +public abstract class TacletIndex implements RuleIndex { private static final Object DEFAULT_SV_KEY = new Object(); private static final Object DEFAULT_PROGSV_KEY = new Object(); @@ -158,6 +159,7 @@ private void removeFromMap(NoPosTacletApp tacletApp, * * @param tacletAppList the NoPosTacletApps to be added */ + @Override public void addTaclets(Iterable tacletAppList) { tacletAppList.forEach(this::add); } @@ -176,8 +178,9 @@ public static ImmutableSet toNoPosTacletApp(Iterable rul * * @param taclet the Taclet and its instantiation info to be added */ - public void add(Taclet taclet) { - add(NoPosTacletApp.createNoPosTacletApp(taclet)); + @Override + public void add(org.key_project.prover.rules.Rule taclet) { + add(NoPosTacletApp.createNoPosTacletApp((Taclet) taclet)); } /** @@ -186,6 +189,7 @@ public void add(Taclet taclet) { * * @param tacletApp the Taclet and its instantiation info to be added */ + @Override public void add(NoPosTacletApp tacletApp) { Taclet taclet = tacletApp.taclet(); switch (taclet) { @@ -208,6 +212,7 @@ public void add(NoPosTacletApp tacletApp) { * * @param tacletApp the Taclet and its instantiation info to be removed */ + @Override public void remove(NoPosTacletApp tacletApp) { Taclet rule = tacletApp.taclet(); switch (rule) { @@ -231,19 +236,18 @@ public void remove(NoPosTacletApp tacletApp) { * * @param tacletAppList the NoPosTacletApps to be removed */ + @Override public void removeTaclets(Iterable tacletAppList) { tacletAppList.forEach(this::remove); } - /** copies the index */ - public abstract TacletIndex copy(); - /** clones the index */ @Override public Object clone() { return this.copy(); } + @Override public Set allNoPosTacletApps() { Set result = new LinkedHashSet<>(); for (ImmutableList tacletApps : rwList.values()) { @@ -272,7 +276,7 @@ public Set allNoPosTacletApps() { */ private ImmutableList getFindTaclet(ImmutableList taclets, RuleFilter filter, PosInOccurrence pos, - Services services) { + LogicServices services) { return matchTaclets(taclets, filter, pos, services); } @@ -282,7 +286,7 @@ private ImmutableList getFindTaclet(ImmutableList matchTaclets( ImmutableList tacletApps, final RuleFilter p_filter, - final PosInOccurrence pos, final Services services); + final PosInOccurrence pos, final LogicServices services); /** * returns a selection from the given map with NoPosTacletApps relevant for the given program @@ -409,9 +413,10 @@ private ImmutableList getList( * @return IList containing all applicable rules and the corresponding * instantiations to get the rule fit. */ + @Override public ImmutableList getAntecedentTaclet( PosInOccurrence pos, RuleFilter filter, - Services services) { + LogicServices services) { return getTopLevelTaclets(antecList, filter, pos, services); } @@ -425,16 +430,17 @@ public ImmutableList getAntecedentTaclet( * @return IList containing all applicable rules and the corresponding * instantiations to get the rule fit. */ + @Override public ImmutableList getSuccedentTaclet( PosInOccurrence pos, RuleFilter filter, - Services services) { + LogicServices services) { return getTopLevelTaclets(succList, filter, pos, services); } private ImmutableList getTopLevelTaclets( HashMap> findTaclets, RuleFilter filter, - PosInOccurrence pos, Services services) { + PosInOccurrence pos, LogicServices services) { assert pos.isTopLevel(); @@ -456,8 +462,9 @@ private ImmutableList getTopLevelTaclets( * @return IList containing all applicable rules and the corresponding * instantiations to get the rule fit. */ + @Override public ImmutableList getRewriteTaclet(PosInOccurrence pos, RuleFilter filter, - Services services) { + LogicServices services) { return matchTaclets(getList(rwList, (JTerm) pos.subTerm(), false), filter, pos, services); } @@ -471,7 +478,9 @@ public ImmutableList getRewriteTaclet(PosInOccurrence pos, RuleF * @return IList containing all applicable rules and an empty part for the * instantiations because no instantiations are necessary. */ - public ImmutableList getNoFindTaclet(RuleFilter filter, Services services) { + @Override + public ImmutableList getNoFindTaclet(RuleFilter filter, + LogicServices services) { return matchTaclets(noFindList, filter, null, services); } @@ -483,6 +492,7 @@ public ImmutableList getNoFindTaclet(RuleFilter filter, Services * @param name the name to lookup * @return the found NoPosTacletApp or null if no matching Taclet is there */ + @Override public NoPosTacletApp lookup(Name name) { for (NoPosTacletApp tacletApp : allNoPosTacletApps()) { if (tacletApp.taclet().name().equals(name)) { @@ -500,6 +510,7 @@ public NoPosTacletApp lookup(Name name) { * @param name the name to lookup * @return the found NoPosTacletApp or null if no matching Taclet is there */ + @Override public @Nullable NoPosTacletApp lookup(String name) { return lookup(new Name(name)); } @@ -509,6 +520,7 @@ public NoPosTacletApp lookup(Name name) { * * @return set with all partial instantiated NoPosTacletApps */ + @Override public Set getPartialInstantiatedApps() { return Collections.unmodifiableSet(partialInstantiatedRuleApps); } From c516fdadf3fd84896ce81c4d014189c1bab96a29 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 13:48:40 +0200 Subject: [PATCH 06/62] Cleanup TacletApp implementations uniform treatment of checkVarCondNotFreeIn --- .../key/proof/MultiThreadedTacletIndex.java | 4 +- .../key/proof/SingleThreadedTacletIndex.java | 2 +- .../de/uka/ilkd/key/rule/NoPosTacletApp.java | 58 +++------------ .../de/uka/ilkd/key/rule/PosTacletApp.java | 11 +-- .../java/de/uka/ilkd/key/rule/TacletApp.java | 72 ++++++++++--------- .../rule/UninstantiatedNoPosTacletApp.java | 4 +- .../ilkd/key/rule/inst/SVInstantiations.java | 13 ++-- .../rules/instantiation/SVInstantiations.java | 3 +- 8 files changed, 67 insertions(+), 100 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java index 5abc180bfc..07bf07fe82 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java @@ -20,8 +20,8 @@ import org.key_project.util.collection.ImmutableSLList; /** - * A multi-threaded taclet index implementation. It executes method - * {@link #matchTaclets(ImmutableList, RuleFilter, PosInOccurrence, Services)} + * A multithreaded taclet index implementation. It executes method + * {@link #matchTaclets(ImmutableList, RuleFilter, PosInOccurrence, LogicServices)} * using multiple * threads (depending on the number of taclets being matched and number of available processors). * diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java index 9087d54d5c..1ed25841df 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java @@ -18,7 +18,7 @@ /** * The default taclet index implementation. It executes method - * {@link #matchTaclets(ImmutableList, RuleFilter, PosInOccurrence, Services)} + * {@link #matchTaclets(ImmutableList, RuleFilter, PosInOccurrence, LogicServices)} * in a single thread * (the thread invoking the method). * diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java index 7e87767224..9dc1713a19 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java @@ -8,10 +8,10 @@ import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.RenameTable; -import de.uka.ilkd.key.logic.TermServices; import de.uka.ilkd.key.logic.op.*; import de.uka.ilkd.key.util.Debug; +import org.key_project.logic.LogicServices; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; @@ -74,7 +74,7 @@ public static NoPosTacletApp createNoPosTacletApp(org.key_project.prover.rules.T "If instantiations list has wrong size"); SVInstantiations inst = resolveCollisionVarSV(taclet, instantiations, services); - if (checkVarCondNotFreeIn(taclet, inst)) { + if (checkVarCondNotFreeIn(taclet, inst, null)) { return new NoPosTacletApp(taclet, inst, assumesInstantiations); } return null; @@ -124,44 +124,6 @@ private NoPosTacletApp(org.key_project.prover.rules.Taclet taclet, super(taclet, instantiations, ifInstantiations); } - - /** - * checks if the variable conditions of type 'x not free in y' are hold by the found - * instantiations. The variable conditions is used implicit in the prefix. (Used to calculate - * the prefix) - * - * @param taclet the Taclet that is tried to be instantiated. A match for the find (or/and if) - * has been found. - * @param instantiations the SVInstantiations so that the find(if) matches - * @return true iff all variable conditions x not free in y are hold - */ - protected static boolean checkVarCondNotFreeIn(org.key_project.prover.rules.Taclet taclet, - SVInstantiations instantiations) { - for (var pair : instantiations.getInstantiationMap()) { - final var sv = pair.key(); - - if (sv instanceof ModalOperatorSV || sv instanceof ProgramSV || sv instanceof VariableSV - || sv instanceof SkolemTermSV) { - continue; - } - - final var prefix = taclet.getPrefix(sv); - if (prefix.context()) { - continue; - } - - final ImmutableSet boundVarSet = - boundAtOccurrenceSet((TacletPrefix) prefix, instantiations); - final JTerm inst = (JTerm) instantiations.getInstantiation(sv); - if (!inst.freeVars().subset(boundVarSet)) { - return false; - } - } - - return true; - } - - /** * adds a new instantiation to this TacletApp * @@ -234,10 +196,10 @@ protected TacletApp setInstantiation(SVInstantiations svi, Services services) { * metavariables given by the mc object and forget the old ones */ @Override - public TacletApp setMatchConditions(MatchResultInfo mc, Services services) { + public TacletApp setMatchConditions(MatchResultInfo mc, LogicServices services) { return createNoPosTacletApp(taclet(), mc.getInstantiations(), assumesFormulaInstantiations(), - services); + (Services) services); } @@ -294,23 +256,22 @@ public PosInOccurrence posInOccurrence() { * * @return TacletApp with the resulting instantiations or null */ - public NoPosTacletApp matchFind(PosInOccurrence pos, Services services) { + public NoPosTacletApp matchFind(PosInOccurrence pos, LogicServices services) { return matchFind(pos, services, null); } - /* * This is a short-circuit version of matchFind(). It helps eliminate numerous calls to the * expensive pos.subTerm() while matching during a recursive descent in a term (where the * current subterm is known anyway). */ public NoPosTacletApp matchFind(PosInOccurrence pos, - Services services, JTerm t) { + LogicServices services, JTerm t) { if ((t == null) && (pos != null)) { t = (JTerm) pos.subTerm(); } - MatchResultInfo mc = setupMatchConditions(pos, services); + MatchResultInfo mc = setupMatchConditions(pos); if (mc == null) { return null; @@ -328,7 +289,7 @@ public NoPosTacletApp matchFind(PosInOccurrence pos, } else { res = mc; } - return evalCheckRes(res, services); + return evalCheckRes(res, (Services) services); } private NoPosTacletApp evalCheckRes(MatchResultInfo res, Services services) { @@ -349,8 +310,7 @@ private NoPosTacletApp evalCheckRes(MatchResultInfo res, Services services) { } - protected MatchResultInfo setupMatchConditions( - PosInOccurrence pos, TermServices services) { + protected MatchResultInfo setupMatchConditions(PosInOccurrence pos) { var svInst = taclet() instanceof NoFindTaclet ? instantiations() : instantiations().clearUpdateContext(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java index b6f64fc1d5..2d2ea2023e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java @@ -10,6 +10,7 @@ import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.util.Debug; +import org.key_project.logic.LogicServices; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; @@ -54,15 +55,15 @@ public static PosTacletApp createPosTacletApp(FindTaclet taclet, public static PosTacletApp createPosTacletApp(FindTaclet taclet, SVInstantiations instantiations, - ImmutableList ifInstantiations, + ImmutableList assumesInstantiations, PosInOccurrence pos, Services services) { - Debug.assertTrue(ifInstsCorrectSize(taclet, ifInstantiations), + Debug.assertTrue(ifInstsCorrectSize(taclet, assumesInstantiations), "If instantiations list has wrong size"); instantiations = resolveCollisionWithContext(taclet, resolveCollisionVarSV(taclet, instantiations, services), pos, services); if (checkVarCondNotFreeIn(taclet, instantiations, pos)) { - return new PosTacletApp(taclet, instantiations, ifInstantiations, pos); + return new PosTacletApp(taclet, instantiations, assumesInstantiations, pos); } return null; @@ -220,9 +221,9 @@ protected TacletApp setInstantiation(SVInstantiations svi, Services services) { * metavariables given by the mc object and forget the old ones */ @Override - public TacletApp setMatchConditions(MatchResultInfo mc, Services services) { + public TacletApp setMatchConditions(MatchResultInfo mc, LogicServices services) { return createPosTacletApp((FindTaclet) taclet(), mc.getInstantiations(), - assumesFormulaInstantiations(), posInOccurrence(), services); + assumesFormulaInstantiations(), posInOccurrence(), (Services) services); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index 0c13bc5af5..e0f39c8010 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -19,9 +19,11 @@ import de.uka.ilkd.key.rule.inst.SVInstantiations.UpdateLabelPair; import de.uka.ilkd.key.util.Debug; +import org.key_project.logic.LogicServices; import org.key_project.logic.Name; import org.key_project.logic.Named; import org.key_project.logic.Namespace; +import org.key_project.logic.Term; import org.key_project.logic.op.Function; import org.key_project.logic.op.Operator; import org.key_project.logic.op.QuantifiableVariable; @@ -98,18 +100,6 @@ public abstract class TacletApp implements RuleApp { new de.uka.ilkd.key.rule.MatchConditions(this.instantiations, RenameTable.EMPTY_TABLE); } - /** - * collects all bound variables above the occurrence of the schemavariable whose prefix is given - * - * @param prefix the TacletPrefix of the schemavariable - * @param instantiations the SVInstantiations so that the find(if)-expression matches - * @return set of the bound variables - */ - protected static ImmutableSet boundAtOccurrenceSet(TacletPrefix prefix, - SVInstantiations instantiations) { - return collectPrefixInstantiations(prefix, instantiations); - } - /** * collects all bound variables above the occurrence of the schemavariable whose prefix is given * @@ -119,11 +109,12 @@ protected static ImmutableSet boundAtOccurrenceSet(TacletP * @return set of the bound variables */ protected static ImmutableSet boundAtOccurrenceSet(TacletPrefix prefix, - SVInstantiations instantiations, PosInOccurrence pos) { + SVInstantiations instantiations, @Nullable PosInOccurrence pos) { - ImmutableSet result = boundAtOccurrenceSet(prefix, instantiations); + ImmutableSet result = + collectPrefixInstantiations(prefix, instantiations); - if (prefix.context()) { + if (pos != null && prefix.context()) { result = result.union(collectBoundVarsAbove(pos)); } @@ -150,6 +141,8 @@ private static ImmutableSet collectPrefixInstantiations(Ta return instanceSet; } + + /** * returns the taclet the application information is collected for * @@ -204,7 +197,7 @@ protected static SVInstantiations resolveCollisionVarSV( for (var pair : insts.getInstantiationMap()) { if (pair.key() instanceof VariableSV varSV) { - JTerm value = (JTerm) pair.value().getInstantiation(); + final Term value = (Term) pair.value().getInstantiation(); if (!collMap.containsKey(value.op())) { collMap.put((LogicVariable) value.op(), varSV); } else { @@ -312,7 +305,7 @@ private static de.uka.ilkd.key.rule.inst.SVInstantiations replaceInstantiation( if (!(t.op() instanceof VariableSV)) { ClashFreeSubst cfSubst = new ClashFreeSubst(x, y, services.getTermBuilder()); result = - result.replace(sv, cfSubst.apply((JTerm) insts.getInstantiation(sv)), services); + result.replace(sv, cfSubst.apply(insts.getInstantiation(sv)), services); } } else { for (int i = 0; i < t.arity(); i++) { @@ -803,7 +796,7 @@ public TacletApp addInstantiation(SchemaVariable sv, Name name, Services service * creates a new Taclet application containing all the instantiations, constraints and new * metavariables given by the mc object and forget the old ones */ - public abstract TacletApp setMatchConditions(MatchResultInfo mc, Services services); + public abstract TacletApp setMatchConditions(MatchResultInfo mc, LogicServices services); /** * creates a new Taclet application containing all the instantiations, constraints, new @@ -943,7 +936,7 @@ private ImmutableList createSemisequentList( * *

* CAUTION: If you call this method, consider to call - * {@link NoPosTacletApp#matchFind(PosInOccurrence, Services)} + * {@link NoPosTacletApp#matchFind(PosInOccurrence, LogicServices)} * first (if applicable) as * otherwise the TacletApp may become invalid. (This happened sometimes during interactive * proofs). @@ -1173,27 +1166,40 @@ public ProgramElement getProgramElement(String instantiation, ProgramSV sv, * instantiations. The variable conditions is used implicit in the prefix. (Used to calculate * the prefix) * - * @param taclet the Taclet that is tried to be instantiated. A match for the find (or/and if) + * @param taclet the Taclet that is tried to be instantiated. A match for the find (or/and + * assumes) * has been found. - * @param instantiations the SVInstantiations so that the find(if) expression matches - * @param pos the PosInOccurrence where the Taclet is applied + * @param instantiations the SVInstantiations so that the find expression or assumes sequent + * matches + * @param pos the PosInOccurrence where the Taclet is applied or null if the taclet has no find * @return true iff all variable conditions x not free in y are hold */ - public static boolean checkVarCondNotFreeIn(org.key_project.prover.rules.Taclet taclet, + protected static boolean checkVarCondNotFreeIn(org.key_project.prover.rules.Taclet taclet, SVInstantiations instantiations, - PosInOccurrence pos) { - final var it = ((de.uka.ilkd.key.rule.inst.SVInstantiations) instantiations).svIterator(); - while (it.hasNext()) { - var sv = it.next(); - if (sv instanceof TermSV || sv instanceof FormulaSV) { - if (!((JTerm) instantiations.getInstantiation(sv)).freeVars() - .subset(boundAtOccurrenceSet((TacletPrefix) taclet.getPrefix(sv), - instantiations, pos))) { + @Nullable PosInOccurrence pos) { - return false; - } + for (var pair : instantiations.getInstantiationMap()) { + final var sv = pair.key(); + + if (sv instanceof ModalOperatorSV || sv instanceof ProgramSV || sv instanceof VariableSV + || sv instanceof SkolemTermSV) { + continue; + } + + final var prefix = taclet.getPrefix(sv); + + if (pos == null && prefix.context()) { + continue; + } + + final ImmutableSet boundVarSet = + boundAtOccurrenceSet((TacletPrefix) prefix, instantiations, pos); + final Term inst = instantiations.getInstantiation(sv); + if (!inst.freeVars().subset(boundVarSet)) { + return false; } } + return true; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/UninstantiatedNoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/UninstantiatedNoPosTacletApp.java index 24802f47eb..cd5a9f6739 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/UninstantiatedNoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/UninstantiatedNoPosTacletApp.java @@ -3,8 +3,6 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.rule; -import de.uka.ilkd.key.logic.TermServices; - import org.key_project.prover.sequent.PosInOccurrence; @@ -29,7 +27,7 @@ class UninstantiatedNoPosTacletApp extends NoPosTacletApp { * PosInOccurrence, de.uka.ilkd.key.java.Services, de.uka.ilkd.key.logic.Constraint) */ @Override - protected MatchConditions setupMatchConditions(PosInOccurrence pos, TermServices services) { + protected MatchConditions setupMatchConditions(PosInOccurrence pos) { if (taclet() instanceof RewriteTaclet) { return ((RewriteTaclet) taclet()).checkPrefix(pos, MatchConditions.EMPTY_MATCHCONDITIONS); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java index 9044d0e67b..fc4bac37b3 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java @@ -544,10 +544,11 @@ public boolean equals(Object obj) { public int hashCode() { int result = 37 * getUpdateContext().hashCode() + size(); - final Iterator>> it = + final Iterator>> it = pairIterator(); while (it.hasNext()) { - final ImmutableMapEntry> e = it.next(); + final ImmutableMapEntry<@NonNull SchemaVariable, @NonNull InstantiationEntry> e = + it.next(); if (e.value().getInstantiation() instanceof TermLabel termLabel) { if (!termLabel.isProofRelevant()) { continue; @@ -559,10 +560,10 @@ public int hashCode() { } public SVInstantiations union( - org.key_project.prover.rules.instantiation.SVInstantiations p_other, - LogicServices services) { + org.key_project.prover.rules.instantiation.@NonNull SVInstantiations p_other, + @NonNull LogicServices services) { final var other = (SVInstantiations) p_other; - ImmutableMap> result = map; + ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> result = map; for (ImmutableMapEntry> entry : other.map) { result = result.put(entry.key(), entry.value()); @@ -584,7 +585,7 @@ public SVInstantiations union( .rebuildSorts(services); } - public ImmutableMap> interesting() { + public ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> interesting() { return interesting; } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java index ffae5136cd..bf4edc3408 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java @@ -8,6 +8,7 @@ import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.util.collection.ImmutableMap; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; /// Implementations of this interface know which schema variables have been matched and their @@ -53,7 +54,7 @@ public interface SVInstantiations { /// /// @return a map that contains all instantiated schema variables and their respective /// instantiation - ImmutableMap> getInstantiationMap(); + ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> getInstantiationMap(); /// /// returns a new [SVInstantiations] object that contains all instantiations contained in From 1492521eba4bbfcc61f419bffbec88c0aaa963e7 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 14:17:30 +0200 Subject: [PATCH 07/62] Minor cleanup and nullness annotations --- .../key/proof/MultiThreadedTacletIndex.java | 9 +++--- .../key/proof/SingleThreadedTacletIndex.java | 9 +++--- .../de/uka/ilkd/key/proof/TacletIndex.java | 3 +- .../de/uka/ilkd/key/rule/NoPosTacletApp.java | 20 +++---------- .../de/uka/ilkd/key/rule/PosTacletApp.java | 29 +++++++------------ .../java/de/uka/ilkd/key/rule/TacletApp.java | 14 ++++++++- .../ilkd/key/rule/inst/SVInstantiations.java | 3 +- .../org/key_project/prover/rules/RuleApp.java | 2 ++ 8 files changed, 42 insertions(+), 47 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java index 07bf07fe82..216ae49e6f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/MultiThreadedTacletIndex.java @@ -19,6 +19,8 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSLList; +import org.jspecify.annotations.NonNull; + /** * A multithreaded taclet index implementation. It executes method * {@link #matchTaclets(ImmutableList, RuleFilter, PosInOccurrence, LogicServices)} @@ -70,13 +72,10 @@ public TacletIndex copy() { * {@inheritDoc} */ @Override - protected ImmutableList matchTaclets(ImmutableList tacletApps, + protected ImmutableList matchTaclets( + @NonNull ImmutableList tacletApps, RuleFilter p_filter, PosInOccurrence pos, LogicServices services) { - ImmutableList result = ImmutableSLList.nil(); - if (tacletApps == null) { - return result; - } if (tacletApps.size() > 256) { NoPosTacletApp[] toMatch = tacletApps.toArray(NoPosTacletApp.class); diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java index 1ed25841df..117d533968 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/SingleThreadedTacletIndex.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.HashSet; -import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.rule.NoPosTacletApp; import de.uka.ilkd.key.rule.Taclet; @@ -16,6 +15,8 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSLList; +import org.jspecify.annotations.NonNull; + /** * The default taclet index implementation. It executes method * {@link #matchTaclets(ImmutableList, RuleFilter, PosInOccurrence, LogicServices)} @@ -63,12 +64,10 @@ public TacletIndex copy() { * {@inheritDoc} */ @Override - protected ImmutableList matchTaclets(ImmutableList tacletApps, + protected ImmutableList matchTaclets( + @NonNull ImmutableList tacletApps, RuleFilter p_filter, PosInOccurrence pos, LogicServices services) { ImmutableList result = ImmutableSLList.nil(); - if (tacletApps == null) { - return result; - } for (final NoPosTacletApp tacletApp : tacletApps) { if (!p_filter.filter(tacletApp.taclet())) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java index f8bbe11ea8..45fd8bd0fe 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java @@ -28,6 +28,7 @@ import org.key_project.util.collection.ImmutableSLList; import org.key_project.util.collection.ImmutableSet; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; /** @@ -285,7 +286,7 @@ private ImmutableList getFindTaclet(ImmutableList matchTaclets( - ImmutableList tacletApps, final RuleFilter p_filter, + @NonNull ImmutableList tacletApps, final RuleFilter p_filter, final PosInOccurrence pos, final LogicServices services); /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java index 9dc1713a19..cad9e2ddc7 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java @@ -8,10 +8,10 @@ import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.RenameTable; -import de.uka.ilkd.key.logic.op.*; import de.uka.ilkd.key.util.Debug; import org.key_project.logic.LogicServices; +import org.key_project.logic.Term; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; @@ -22,6 +22,7 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSet; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -132,7 +133,7 @@ private NoPosTacletApp(org.key_project.prover.rules.Taclet taclet, * @return the new TacletApp */ @Override - public TacletApp addInstantiation(SchemaVariable sv, JTerm term, boolean interesting, + public TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interesting, Services services) { if (interesting) { return createNoPosTacletApp(taclet(), @@ -215,24 +216,11 @@ protected TacletApp setAllInstantiations(MatchResultInfo mc, } - /** - * returns true iff all necessary information is collected, so that the Taclet can be applied. - * - * @return true iff all necessary information is collected, so that the Taclet can be applied. - */ - @Override - public boolean complete() { - return (uninstantiatedVars().isEmpty() && taclet() instanceof NoFindTaclet - && assumesInstantionsComplete()); - - } - @Override protected ImmutableSet contextVars(SchemaVariable sv) { return DefaultImmutableSet.nil(); } - /** * returns the PositionInOccurrence (representing a SequentFormula and a position in the * corresponding formula) @@ -240,7 +228,7 @@ protected ImmutableSet contextVars(SchemaVariable sv) { * @return the PosInOccurrence */ @Override - public PosInOccurrence posInOccurrence() { + public @Nullable PosInOccurrence posInOccurrence() { return null; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java index 2d2ea2023e..458e54150d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java @@ -11,8 +11,10 @@ import de.uka.ilkd.key.util.Debug; import org.key_project.logic.LogicServices; +import org.key_project.logic.Term; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; +import org.key_project.prover.rules.TacletPrefix; import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; import org.key_project.prover.rules.instantiation.MatchResultInfo; import org.key_project.prover.rules.instantiation.SVInstantiations; @@ -21,6 +23,8 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSet; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + /** * A position taclet application object, contains already the information to which term/formula of * the sequent the taclet is attached. The position information has been determined by matching the @@ -35,7 +39,7 @@ public class PosTacletApp extends TacletApp { * stores the information where the Taclet is to be applied. This means where the find section * of the taclet matches */ - private final PosInOccurrence pos; + private final @MonotonicNonNull PosInOccurrence pos; /** * creates a PosTacletApp for the given taclet with some known instantiations and a position @@ -115,7 +119,9 @@ private static Iterator allVariableSV(Taclet taclet) { @Override protected ImmutableSet contextVars(SchemaVariable sv) { - if (!taclet().getPrefix(sv).context()) { + final TacletPrefix prefix = taclet().getPrefix(sv); + assert prefix != null : "prefix should not be null for taclets with a find"; + if (!prefix.context()) { return DefaultImmutableSet.nil(); } return varsBoundAboveFindPos(taclet(), posInOccurrence()); @@ -136,7 +142,7 @@ private static SVInstantiations resolveCollisionWithContext(Taclet taclet, Iterator it = allVariableSV(taclet); while (it.hasNext()) { SchemaVariable varSV = it.next(); - JTerm inst = (JTerm) insts.getInstantiation(varSV); + JTerm inst = insts.getInstantiation(varSV); if (inst != null && k.contains(inst.op())) { insts = replaceInstantiation(taclet, insts, varSV, services); } @@ -154,9 +160,8 @@ private static SVInstantiations resolveCollisionWithContext(Taclet taclet, * @return the new TacletApp */ @Override - public TacletApp addInstantiation(SchemaVariable sv, JTerm term, boolean interesting, + public TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interesting, Services services) { - if (interesting) { return createPosTacletApp((FindTaclet) taclet(), instantiations().addInteresting(sv, term, services), assumesFormulaInstantiations(), @@ -240,18 +245,6 @@ protected TacletApp setAllInstantiations(MatchResultInfo mc, posInOccurrence(), services); } - - /** - * returns true iff all necessary information is collected, so that the Taclet can be applied. - * - * @return true iff all necessary information is collected, so that the Taclet can be applied. - */ - @Override - public boolean complete() { - return posInOccurrence() != null && uninstantiatedVars().isEmpty() - && assumesInstantionsComplete(); - } - /** * returns the PositionInOccurrence (representing a SequentFormula and a position in the * corresponding formula) @@ -259,7 +252,7 @@ public boolean complete() { * @return the PosInOccurrence */ @Override - public PosInOccurrence posInOccurrence() { + public @MonotonicNonNull PosInOccurrence posInOccurrence() { return pos; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index e0f39c8010..61e4768d44 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -703,6 +703,18 @@ public void registerSkolemConstants(Namespace<@NonNull Function> fns) { } } + /** + * returns true iff all necessary information is collected, so that the Taclet can be applied. + * + * @return true iff all necessary information is collected, so that the Taclet can be applied. + */ + @Override + public final boolean complete() { + return (posInOccurrence() != null || taclet instanceof NoFindTaclet) + && uninstantiatedVars().isEmpty() + && assumesInstantionsComplete(); + } + /** * adds a new instantiation to this TacletApp * @@ -710,7 +722,7 @@ public void registerSkolemConstants(Namespace<@NonNull Function> fns) { * @param term the Term the SchemaVariable is instantiated with * @return the new TacletApp */ - public abstract TacletApp addInstantiation(SchemaVariable sv, JTerm term, boolean interesting, + public abstract TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interesting, Services services); /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java index fc4bac37b3..b78e035713 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java @@ -20,6 +20,7 @@ import org.key_project.logic.LogicServices; import org.key_project.logic.Name; import org.key_project.logic.SyntaxElement; +import org.key_project.logic.Term; import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.instantiation.IllegalInstantiationException; import org.key_project.prover.rules.instantiation.InstantiationEntry; @@ -137,7 +138,7 @@ public SVInstantiations add(SchemaVariable sv, SyntaxElement matchedElement, return add(sv, new InstantiationEntry<>(matchedElement), services); } - public SVInstantiations addInteresting(SchemaVariable sv, JTerm subst, LogicServices services) { + public SVInstantiations addInteresting(SchemaVariable sv, Term subst, LogicServices services) { return addInteresting(sv, new InstantiationEntry<>(subst), services); } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/RuleApp.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/RuleApp.java index 35cb9715bf..08044ca443 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/RuleApp.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/RuleApp.java @@ -8,6 +8,7 @@ import org.key_project.prover.sequent.PosInOccurrence; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; /// Instances of this type accumulate the information for a specific rule application /// like application position, instantiations and more. @@ -44,5 +45,6 @@ default String displayName() { /// the position where to apply the rule to which this application belongs /// /// @return the [PosInOccurrence] with the position information + @Nullable PosInOccurrence posInOccurrence(); } From 7e70c11de00a8fe616a1f33ead9034f6c4b5dc62 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 14:27:16 +0200 Subject: [PATCH 08/62] Simplify "union" logic in SVInstantiations --- .../de/uka/ilkd/key/rule/NoPosTacletApp.java | 4 --- .../ilkd/key/rule/inst/SVInstantiations.java | 27 ++++++++----------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java index cad9e2ddc7..618f594596 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java @@ -164,7 +164,6 @@ public TacletApp addInstantiation(SchemaVariable sv, ProgramElement pe, boolean } } - /** * creates a new Taclet application containing all the instantiations given by the * SVInstantiations and hold the old ones @@ -191,7 +190,6 @@ protected TacletApp setInstantiation(SVInstantiations svi, Services services) { return new NoPosTacletApp(taclet(), svi, assumesFormulaInstantiations()); } - /** * creates a new Taclet application containing all the instantiations, constraints and new * metavariables given by the mc object and forget the old ones @@ -203,7 +201,6 @@ public TacletApp setMatchConditions(MatchResultInfo mc, LogicServices services) (Services) services); } - /** * creates a new Taclet application containing all the instantiations, constraints, new * metavariables and if formula instantiations given and forget the old ones @@ -215,7 +212,6 @@ protected TacletApp setAllInstantiations(MatchResultInfo mc, services); } - @Override protected ImmutableSet contextVars(SchemaVariable sv) { return DefaultImmutableSet.nil(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java index b78e035713..b62e2bf597 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java @@ -15,7 +15,6 @@ import de.uka.ilkd.key.logic.label.TermLabel; import de.uka.ilkd.key.logic.op.*; import de.uka.ilkd.key.logic.sort.ProgramSVSort; -import de.uka.ilkd.key.util.Debug; import org.key_project.logic.LogicServices; import org.key_project.logic.Name; @@ -61,13 +60,13 @@ public boolean canStandFor(ProgramElement pe, Services services) { /** the map with the instantiations to logic terms */ - private final ImmutableMap> map; + private final ImmutableMap<@NonNull SchemaVariable, InstantiationEntry> map; /** * just a list of "interesting" instantiations: these instantiations are not 100% predetermined * and worth saving in a proof */ - private final ImmutableMap> interesting; + private final ImmutableMap<@NonNull SchemaVariable, InstantiationEntry> interesting; /** * updates may be ignored when matching, therefore they need to be added after the application @@ -82,7 +81,7 @@ public boolean canStandFor(ProgramElement pe, Services services) { /** additional conditions for the generic sorts */ private final ImmutableList genericSortConditions; - /** creates a new SVInstantions object with an empty map */ + /** creates a new SVInstantiations object with an empty map */ private SVInstantiations() { genericSortConditions = ImmutableSLList.nil(); updateContext = ImmutableSLList.nil(); @@ -244,8 +243,8 @@ public SVInstantiations addInteresting(SchemaVariable sv, InstantiationEntry } public SVInstantiations addInteresting(SchemaVariable sv, Name name, LogicServices services) { - SchemaVariable existingSV = lookupVar(sv.name()); - Name oldValue = (Name) getInstantiation(existingSV); + final SchemaVariable existingSV = lookupVar(sv.name()); + final Name oldValue = getInstantiation(existingSV); if (name.equals(oldValue)) { return this; // already have it } else if (oldValue != null) { @@ -570,17 +569,13 @@ public SVInstantiations union( result = result.put(entry.key(), entry.value()); } - ImmutableList updates = ImmutableSLList.nil(); + ImmutableList updates = updateContext; - if (other.getUpdateContext().isEmpty()) { - updates = getUpdateContext(); - } else if (getUpdateContext().isEmpty()) { - updates = other.getUpdateContext(); - } else if (!getUpdateContext().equals(other.getUpdateContext())) { - Debug.fail( - "The update context of one of" + " the instantiations has to be empty or equal."); - } else { - updates = other.getUpdateContext(); + if (updates.isEmpty()) { + updates = other.updateContext; + } else if (!updateContext.equals(other.updateContext)) { + throw new IllegalArgumentException( + "The update context of one of the instantiations has to be empty or equal."); } return new SVInstantiations(result, interesting(), updates, getGenericSortConditions()) .rebuildSorts(services); From 1e357faa5652fe1b5c2a63141b83c8a3925637e4 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 14:48:08 +0200 Subject: [PATCH 09/62] Nullness and cleanup of code --- .../de/uka/ilkd/key/rule/NoPosTacletApp.java | 61 ++++------ .../de/uka/ilkd/key/rule/PosTacletApp.java | 25 +---- .../de/uka/ilkd/key/rule/RewriteTaclet.java | 3 +- .../java/de/uka/ilkd/key/rule/TacletApp.java | 19 +--- .../ilkd/key/rule/inst/SVInstantiations.java | 105 ++++++++---------- .../rules/instantiation/SVInstantiations.java | 7 +- 6 files changed, 83 insertions(+), 137 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java index 618f594596..ed75b2cd9d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java @@ -11,6 +11,7 @@ import de.uka.ilkd.key.util.Debug; import org.key_project.logic.LogicServices; +import org.key_project.logic.SyntaxElement; import org.key_project.logic.Term; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; @@ -129,37 +130,22 @@ private NoPosTacletApp(org.key_project.prover.rules.Taclet taclet, * adds a new instantiation to this TacletApp * * @param sv the SchemaVariable to be instantiated - * @param term the Term the SchemaVariable is instantiated with + * @param se the SyntaxElement (usually a {@link Term} or {@link ProgramElement}) + * with which the SV is instantiated + * @param interesting a marker whether the instantiation needs to be stored explicitly when + * saving a proof; this is usually needed for new names as their creation + * is not always deterministic + * @param services the Services for access to the logic signature and more * @return the new TacletApp */ @Override - public TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interesting, + public TacletApp addInstantiation(SchemaVariable sv, SyntaxElement se, boolean interesting, Services services) { if (interesting) { - return createNoPosTacletApp(taclet(), - instantiations().addInteresting(sv, term, services), assumesFormulaInstantiations(), - services); - } else { - return createNoPosTacletApp(taclet(), instantiations().add(sv, term, services), - assumesFormulaInstantiations(), services); - } - } - - /** - * adds a new instantiation to this TacletApp - * - * @param sv the SchemaVariable to be instantiated - * @param pe the ProgramElement with which the SV is instantiated - * @return the new TacletApp - */ - @Override - public TacletApp addInstantiation(SchemaVariable sv, ProgramElement pe, boolean interesting, - Services services) { - if (interesting) { - return createNoPosTacletApp(taclet(), instantiations().addInteresting(sv, pe, services), + return createNoPosTacletApp(taclet(), instantiations().addInteresting(sv, se, services), assumesFormulaInstantiations(), services); } else { - return createNoPosTacletApp(taclet(), instantiations().add(sv, pe, services), + return createNoPosTacletApp(taclet(), instantiations().add(sv, se, services), assumesFormulaInstantiations(), services); } } @@ -177,7 +163,6 @@ public TacletApp addInstantiation(SVInstantiations svi, Services services) { assumesFormulaInstantiations()); } - /** * creates a new Taclet application containing all the instantiations given by the * SVInstantiations and forget the ones in this TacletApp @@ -241,7 +226,7 @@ protected ImmutableSet contextVars(SchemaVariable sv) { * @return TacletApp with the resulting instantiations or null */ public NoPosTacletApp matchFind(PosInOccurrence pos, LogicServices services) { - return matchFind(pos, services, null); + return matchFind(null, pos, services); } /* @@ -249,10 +234,10 @@ public NoPosTacletApp matchFind(PosInOccurrence pos, LogicServices services) { * expensive pos.subTerm() while matching during a recursive descent in a term (where the * current subterm is known anyway). */ - public NoPosTacletApp matchFind(PosInOccurrence pos, - LogicServices services, JTerm t) { - if ((t == null) && (pos != null)) { - t = (JTerm) pos.subTerm(); + private NoPosTacletApp matchFind(@Nullable JTerm termToBeMatched, PosInOccurrence pos, + LogicServices services) { + if ((termToBeMatched == null) && (pos != null)) { + termToBeMatched = (JTerm) pos.subTerm(); } MatchResultInfo mc = setupMatchConditions(pos); @@ -263,7 +248,7 @@ public NoPosTacletApp matchFind(PosInOccurrence pos, MatchResultInfo res; if (taclet() instanceof FindTaclet) { - res = taclet().getMatcher().matchFind(t, mc, services); + res = taclet().getMatcher().matchFind(termToBeMatched, mc, services); // the following check will partly be repeated within the // constructor; this could be optimised if (res == null || !checkVarCondNotFreeIn(taclet(), @@ -282,7 +267,7 @@ private NoPosTacletApp evalCheckRes(MatchResultInfo res, Services services) { } if (updateContextFixed - && !updateContextCompatible((de.uka.ilkd.key.rule.MatchConditions) res)) { + && !updateContextCompatible((MatchConditions) res)) { /* * LOGGER.debug("NoPosTacletApp: Incompatible context", instantiations.getUpdateContext * (), res.matchConditions().getInstantiations().getUpdateContext()); @@ -298,22 +283,22 @@ protected MatchResultInfo setupMatchConditions(PosInOccurrence pos) { var svInst = taclet() instanceof NoFindTaclet ? instantiations() : instantiations().clearUpdateContext(); - de.uka.ilkd.key.rule.MatchConditions mc; + MatchConditions mc; if (svInst.isEmpty()) { - mc = de.uka.ilkd.key.rule.MatchConditions.EMPTY_MATCHCONDITIONS; + mc = MatchConditions.EMPTY_MATCHCONDITIONS; } else { - mc = new de.uka.ilkd.key.rule.MatchConditions(svInst, RenameTable.EMPTY_TABLE); + mc = new MatchConditions(svInst, RenameTable.EMPTY_TABLE); } - if (taclet() instanceof RewriteTaclet) { - mc = ((RewriteTaclet) taclet()).checkPrefix(pos, mc); + if (taclet() instanceof RewriteTaclet rewriteTaclet) { + mc = rewriteTaclet.checkPrefix(pos, mc); } return mc; } - private boolean updateContextCompatible(de.uka.ilkd.key.rule.MatchConditions p_mc) { + private boolean updateContextCompatible(MatchConditions p_mc) { return instantiations.getUpdateContext() .equals(p_mc.getInstantiations().getUpdateContext()); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java index 458e54150d..2f5680f22b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java @@ -5,13 +5,12 @@ import java.util.Iterator; -import de.uka.ilkd.key.java.ProgramElement; import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.util.Debug; import org.key_project.logic.LogicServices; -import org.key_project.logic.Term; +import org.key_project.logic.SyntaxElement; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.TacletPrefix; @@ -160,7 +159,7 @@ private static SVInstantiations resolveCollisionWithContext(Taclet taclet, * @return the new TacletApp */ @Override - public TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interesting, + public TacletApp addInstantiation(SchemaVariable sv, SyntaxElement term, boolean interesting, Services services) { if (interesting) { return createPosTacletApp((FindTaclet) taclet(), @@ -173,26 +172,6 @@ public TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interest } } - /** - * adds a new instantiation to this TacletApp - * - * @param sv the SchemaVariable to be instantiated - * @param pe the ProgramElement the SV is instantiated with - * @return the new TacletApp - */ - @Override - public TacletApp addInstantiation(SchemaVariable sv, ProgramElement pe, boolean interesting, - Services services) { - if (interesting) { - return createPosTacletApp((FindTaclet) taclet(), - instantiations().addInteresting(sv, pe, services), assumesFormulaInstantiations(), - posInOccurrence(), services); - } else { - return createPosTacletApp((FindTaclet) taclet(), instantiations().add(sv, pe, services), - assumesFormulaInstantiations(), posInOccurrence(), services); - } - } - /** * creates a new Taclet application containing all the instantiations given by the * SVInstantiations and the ones of this TacletApp diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/RewriteTaclet.java b/key.core/src/main/java/de/uka/ilkd/key/rule/RewriteTaclet.java index 3a919be503..95de43b22f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/RewriteTaclet.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/RewriteTaclet.java @@ -126,8 +126,7 @@ public MatchConditions checkPrefix( || veto(t)) { return null; } else { - JTerm update = UpdateApplication.getUpdate(t); - svi = svi.addUpdate(update, t.getLabels()); + svi = svi.addUpdate(UpdateApplication.getUpdate(t), t.getLabels()); } } else if (!applicationRestriction().equals(ApplicationRestriction.NONE) && (op instanceof JModality)) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index 61e4768d44..3528704c90 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -23,6 +23,7 @@ import org.key_project.logic.Name; import org.key_project.logic.Named; import org.key_project.logic.Namespace; +import org.key_project.logic.SyntaxElement; import org.key_project.logic.Term; import org.key_project.logic.op.Function; import org.key_project.logic.op.Operator; @@ -715,31 +716,21 @@ && uninstantiatedVars().isEmpty() && assumesInstantionsComplete(); } - /** - * adds a new instantiation to this TacletApp - * - * @param sv the SchemaVariable to be instantiated - * @param term the Term the SchemaVariable is instantiated with - * @return the new TacletApp - */ - public abstract TacletApp addInstantiation(SchemaVariable sv, Term term, boolean interesting, - Services services); - /** * adds a new instantiation to this TacletApp. This method does not check (beside some very * rudimentary tests) if the instantiation is possible. If you cannot guarantee that adding the - * entry (sv, pe) will result in a valid taclet instantiation, you have to use + * entry (sv, se) will result in a valid taclet instantiation, you have to use * {@link #addCheckedInstantiation(SchemaVariable, ProgramElement, Services, boolean)} instead * * @param sv the SchemaVariable to be instantiated - * @param pe the ProgramElement the SV is instantiated with + * @param se the SyntaxElement the SV is instantiated with * @param interesting a boolean marking if the instantiation of this sv needs to be saved for * later proof loading (interesting==true) or if it can be derived * deterministically (e.g. by matching) ( interesting==false) * @return a new taclet application equal to this one but including the newly added - * instantiation entry (sv, pe) + * instantiation entry (sv, se) */ - public abstract TacletApp addInstantiation(SchemaVariable sv, ProgramElement pe, + public abstract TacletApp addInstantiation(SchemaVariable sv, SyntaxElement se, boolean interesting, Services services); /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java index b62e2bf597..840bccface 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java @@ -53,6 +53,7 @@ public class SVInstantiations */ private static final SchemaVariable CONTEXTSV = SchemaVariableFactory.createProgramSV( new ProgramElementName("Context"), new ProgramSVSort(new Name("ContextStatementBlock")) { + @Override public boolean canStandFor(ProgramElement pe, Services services) { return true; } @@ -60,13 +61,13 @@ public boolean canStandFor(ProgramElement pe, Services services) { /** the map with the instantiations to logic terms */ - private final ImmutableMap<@NonNull SchemaVariable, InstantiationEntry> map; + private final ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> map; /** * just a list of "interesting" instantiations: these instantiations are not 100% predetermined * and worth saving in a proof */ - private final ImmutableMap<@NonNull SchemaVariable, InstantiationEntry> interesting; + private final ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> interesting; /** * updates may be ignored when matching, therefore they need to be added after the application @@ -94,19 +95,21 @@ private SVInstantiations() { * * @param map the ImmMap> with the instantiations */ - private SVInstantiations(ImmutableMap> map, - ImmutableMap> interesting, - ImmutableList updateContext, - ImmutableList genericSortConditions) { + private SVInstantiations( + ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> map, + ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> interesting, + ImmutableList<@NonNull UpdateLabelPair> updateContext, + ImmutableList<@NonNull GenericSortCondition> genericSortConditions) { this(map, interesting, updateContext, GenericSortInstantiations.EMPTY_INSTANTIATIONS, genericSortConditions); } - private SVInstantiations(ImmutableMap> map, - ImmutableMap> interesting, - ImmutableList updateContext, + private SVInstantiations( + ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> map, + ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> interesting, + ImmutableList<@NonNull UpdateLabelPair> updateContext, GenericSortInstantiations genericSortInstantiations, - ImmutableList genericSortConditions) { + ImmutableList<@NonNull GenericSortCondition> genericSortConditions) { this.map = map; this.interesting = interesting; this.updateContext = updateContext; @@ -133,11 +136,12 @@ public ImmutableList getGenericSortConditions() { * @return SVInstantiations the new SVInstantiations containing the given pair */ public SVInstantiations add(SchemaVariable sv, SyntaxElement matchedElement, - LogicServices services) throws SortException { + LogicServices services) { return add(sv, new InstantiationEntry<>(matchedElement), services); } - public SVInstantiations addInteresting(SchemaVariable sv, Term subst, LogicServices services) { + public SVInstantiations addInteresting(SchemaVariable sv, SyntaxElement subst, + LogicServices services) { return addInteresting(sv, new InstantiationEntry<>(subst), services); } @@ -201,7 +205,7 @@ private SVInstantiations checkSorts(SchemaVariable p_sv, InstantiationEntry p private SVInstantiations checkCondition(GenericSortCondition p_c, boolean p_forceRebuild, LogicServices services) { - Boolean b = getGenericSortInstantiations().checkCondition(p_c); + final Boolean b = getGenericSortInstantiations().checkCondition(p_c); if (b == null) { return rebuildSorts(services); @@ -244,15 +248,15 @@ public SVInstantiations addInteresting(SchemaVariable sv, InstantiationEntry public SVInstantiations addInteresting(SchemaVariable sv, Name name, LogicServices services) { final SchemaVariable existingSV = lookupVar(sv.name()); - final Name oldValue = getInstantiation(existingSV); - if (name.equals(oldValue)) { + final Name oldValue = existingSV == null ? null : getInstantiation(existingSV); + if (oldValue == null) { + // otherwise (nothing here yet) add it + return addInteresting(sv, new InstantiationEntry<>(name), services); + } else if (name.equals(oldValue)) { return this; // already have it - } else if (oldValue != null) { + } else { throw new IllegalStateException( "Trying to add a second name proposal for " + sv + ": " + oldValue + "->" + name); - } else { - // otherwise (nothing here yet) add it - return addInteresting(sv, new InstantiationEntry<>(name), services); } } @@ -295,7 +299,7 @@ public SVInstantiations makeInteresting(SchemaVariable sv, LogicServices service * @param sv the SchemaVariable to be instantiated * @param term the Term the SchemaVariable is instantiated with */ - public SVInstantiations replace(SchemaVariable sv, JTerm term, Services services) { + public SVInstantiations replace(SchemaVariable sv, Term term, Services services) { return replace(sv, new InstantiationEntry<>(term), services); } @@ -347,7 +351,8 @@ public SVInstantiations replace(PosInProgram prefix, PosInProgram postfix, * * @return true iff the sv has been instantiated already */ - public boolean isInstantiated(SchemaVariable sv) { + @Override + public boolean isInstantiated(@NonNull SchemaVariable sv) { return map.containsKey(sv); } @@ -369,7 +374,7 @@ public InstantiationEntry getInstantiationEntry(SchemaVariable sv) { * stored */ @Override - public @Nullable T getInstantiation(SchemaVariable sv) { + public @Nullable T getInstantiation(@NonNull SchemaVariable sv) { final InstantiationEntry entry = getInstantiationEntry(sv); return entry == null ? null : entry.getInstantiation(); } @@ -386,8 +391,8 @@ public JTerm getTermInstantiation(SchemaVariable sv, ExecutionContext ec, final Object inst = getInstantiation(sv); if (inst == null) { return null; - } else if (inst instanceof JTerm) { - return (JTerm) inst; + } else if (inst instanceof JTerm term) { + return term; } else if (inst instanceof ProgramElement) { return ((Services) services).getTypeConverter() .convertToLogicElement((ProgramElement) inst, ec); @@ -401,7 +406,7 @@ public JTerm getTermInstantiation(SchemaVariable sv, ExecutionContext ec, * * @param updateApplicationlabels the TermLabels attached to the application operator term */ - public SVInstantiations addUpdate(JTerm update, + public SVInstantiations addUpdate(@NonNull JTerm update, ImmutableArray updateApplicationlabels) { assert update.sort() == JavaDLTheory.UPDATE; return new SVInstantiations(map, interesting(), @@ -409,23 +414,6 @@ public SVInstantiations addUpdate(JTerm update, getGenericSortInstantiations(), getGenericSortConditions()); } - public record UpdateLabelPair(JTerm update, ImmutableArray updateApplicationlabels) { - @Override - public boolean equals(Object obj) { - if (obj instanceof UpdateLabelPair) { - return update.equals(((UpdateLabelPair) obj).update()) && updateApplicationlabels - .equals(((UpdateLabelPair) obj).updateApplicationlabels()); - } else { - return false; - } - } - - @Override - public int hashCode() { - return update.hashCode() + 13 * updateApplicationlabels.hashCode(); - } - } - public SVInstantiations addUpdateList(ImmutableList updates) { if (updates.isEmpty() && updateContext.isEmpty()) { // avoid unnecessary creation of SVInstantiations @@ -476,7 +464,7 @@ public Iterator>> pairIt * * @return the Iterator */ - public ImmutableMap> getInstantiationMap() { + public @NonNull ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> getInstantiationMap() { return map; } @@ -512,6 +500,7 @@ public ImmutableList getUpdateContext() { * * @return true if the given object and this one have the same mappings */ + @Override public boolean equals(Object obj) { final SVInstantiations cmp; if (!(obj instanceof SVInstantiations)) { @@ -523,10 +512,7 @@ public boolean equals(Object obj) { return false; } - final Iterator>> it = - pairIterator(); - while (it.hasNext()) { - final ImmutableMapEntry> e = it.next(); + for (final var e : map) { final Object inst = e.value().getInstantiation(); assert inst != null : "Illegal null instantiation."; if (inst instanceof JTerm instAsTerm) { @@ -542,24 +528,23 @@ public boolean equals(Object obj) { } + @Override public int hashCode() { int result = 37 * getUpdateContext().hashCode() + size(); - final Iterator>> it = - pairIterator(); - while (it.hasNext()) { - final ImmutableMapEntry<@NonNull SchemaVariable, @NonNull InstantiationEntry> e = - it.next(); - if (e.value().getInstantiation() instanceof TermLabel termLabel) { + for (final var e : map) { + final Object instantiation = e.value().getInstantiation(); + if (instantiation instanceof TermLabel termLabel) { if (!termLabel.isProofRelevant()) { continue; } } - result = 37 * result + e.value().getInstantiation().hashCode() + e.key().hashCode(); + result = 37 * result + instantiation.hashCode() + e.key().hashCode(); } return result; } - public SVInstantiations union( + @Override + public @NonNull SVInstantiations union( org.key_project.prover.rules.instantiation.@NonNull SVInstantiations p_other, @NonNull LogicServices services) { final var other = (SVInstantiations) p_other; @@ -595,14 +580,14 @@ public String toString() { /** * Add the given additional condition for the generic sort instantiations */ - public SVInstantiations add(GenericSortCondition p_c, LogicServices services) + public @NonNull SVInstantiations add(GenericSortCondition p_c, LogicServices services) throws SortException { return new SVInstantiations(map, interesting(), getUpdateContext(), getGenericSortInstantiations(), getGenericSortConditions().prepend(p_c)) .checkCondition(p_c, false, services); } - public ExecutionContext getExecutionContext() { + public @Nullable ExecutionContext getExecutionContext() { final ContextStatementBlockInstantiation cte = getContextInstantiation(); if (cte != null) { return cte.activeStatementContext(); @@ -611,7 +596,8 @@ public ExecutionContext getExecutionContext() { } } - public ImmutableMapEntry> lookupEntryForSV(Name name) { + public @Nullable ImmutableMapEntry> lookupEntryForSV( + Name name) { for (ImmutableMapEntry> e : map) { if (e.key().name().equals(name)) { return e; @@ -632,4 +618,7 @@ public ImmutableMapEntry> lookupEntryForSV // e.value() cannot be null here as null instantiations are not allowed return e == null ? null : (T) e.value().getInstantiation(); } + + public record UpdateLabelPair(JTerm update, ImmutableArray updateApplicationlabels) { + } } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java index bf4edc3408..551543d691 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/SVInstantiations.java @@ -21,6 +21,7 @@ public interface SVInstantiations { /// /// @param name Name of the schema variable /// @return the SchemaVariable + @Nullable SchemaVariable lookupVar(Name name); /// checks whether a schema variable of the specified name has been instantiated and @@ -30,6 +31,7 @@ public interface SVInstantiations { /// @return the instantiation of the schema variable, `null` if no instantiation for a /// schema variable of the /// specified name is available + @Nullable T lookupValue(Name name); /// checks whether the given schema variable has been instantiated and @@ -40,20 +42,21 @@ public interface SVInstantiations { /// schema variable is /// available @Nullable - T getInstantiation(SchemaVariable sv); + T getInstantiation(@NonNull SchemaVariable sv); /// checks whether the given schema variable has been instantiated /// /// @param sv the [SchemaVariable] /// @return true if and only if an instantiation of the schema variable is available - boolean isInstantiated(SchemaVariable sv); + boolean isInstantiated(@NonNull SchemaVariable sv); /// returns a map that contains all instantiated schema variables and their respective /// instantiation /// /// @return a map that contains all instantiated schema variables and their respective /// instantiation + @NonNull ImmutableMap<@NonNull SchemaVariable, @NonNull InstantiationEntry> getInstantiationMap(); /// From 07a92f6783d7508ff5f449f0e9b9dbda8591dad4 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 16:10:55 +0200 Subject: [PATCH 10/62] Renaming from ifInstantiation to assumesFormulaInstantiation --- .../java/de/uka/ilkd/key/rule/TacletApp.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index 3528704c90..b8482ee2d7 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -72,7 +72,7 @@ public abstract class TacletApp implements RuleApp { /** * chosen instantiations for the assumes-sequent formulas */ - protected final ImmutableList ifInstantiations; + protected final ImmutableList assumesFormulaInstantiations; /** * set of schema variables that appear in the Taclet and need to be instantiated but are not @@ -93,10 +93,10 @@ public abstract class TacletApp implements RuleApp { } TacletApp(org.key_project.prover.rules.Taclet taclet, SVInstantiations instantiations, - ImmutableList ifInstantiations) { + ImmutableList assumesFormulaInstantiations) { this.taclet = taclet; this.instantiations = (de.uka.ilkd.key.rule.inst.SVInstantiations) instantiations; - this.ifInstantiations = ifInstantiations; + this.assumesFormulaInstantiations = assumesFormulaInstantiations; this.matchConditions = new de.uka.ilkd.key.rule.MatchConditions(this.instantiations, RenameTable.EMPTY_TABLE); } @@ -177,7 +177,7 @@ public de.uka.ilkd.key.rule.MatchConditions matchConditions() { } public ImmutableList assumesFormulaInstantiations() { - return ifInstantiations; + return assumesFormulaInstantiations; } public boolean isUpdateContextFixed() { @@ -823,7 +823,7 @@ public TacletApp setIfFormulaInstantiations(ImmutableList findIfFormulaInstantiations(Sequent seq, Services services) { // TODO Why not return just the list of IfFormulaInstantiations? - Debug.assertTrue(ifInstantiations == null, + Debug.assertTrue(assumesFormulaInstantiations == null, "The if formulas have already been instantiated"); if (taclet().assumesSequent().isEmpty()) { @@ -960,7 +960,7 @@ public PosTacletApp setPosInOccurrence(PosInOccurrence pos, * @return true iff the if-instantiation list is not null or no if sequent is needed */ public boolean assumesInstantionsComplete() { - return ifInstantiations != null || taclet().assumesSequent().isEmpty(); + return assumesFormulaInstantiations != null || taclet().assumesSequent().isEmpty(); } /** @@ -977,7 +977,7 @@ public boolean equals(Object o) { } final TacletApp s = (TacletApp) o; return (s.taclet.equals(taclet) && s.instantiations.equals(instantiations)) - && (Objects.equals(ifInstantiations, s.ifInstantiations)); + && (Objects.equals(assumesFormulaInstantiations, s.assumesFormulaInstantiations)); } @Override @@ -985,7 +985,8 @@ public int hashCode() { int result = 17; result = 37 * result + taclet.hashCode(); result = 37 * result + instantiations.hashCode(); - result = 37 * result + (ifInstantiations == null ? 0 : ifInstantiations.hashCode()); + result = 37 * result + (assumesFormulaInstantiations == null ? 0 + : assumesFormulaInstantiations.hashCode()); return result; } From 0c14224c3eeae5f93664f309f04246631697d9f7 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 17:53:14 +0200 Subject: [PATCH 11/62] Avoid duplicate check of equal sv instantiations --- .../rule/EqualityModuloProofIrrelevancy.java | 8 +-- .../java/de/uka/ilkd/key/rule/TacletApp.java | 55 ++++++++++--------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java b/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java index ebcb447f2c..3b96fd18c1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java @@ -479,12 +479,7 @@ public static boolean equalsModProofIrrelevancy(TacletApp _this, TacletApp that) EqualityModuloProofIrrelevancy::equalsModProofIrrelevancy)) { return false; } - if (!equalsModProofIrrelevancy(_this.instantiations, that.instantiations)) { - return false; - } - final MatchConditions matchConditions = _this.matchConditions(); - if (!equalsModProofIrrelevancy(matchConditions, - that.matchConditions())) { + if (!equalsModProofIrrelevancy(_this.instantiations(), that.instantiations())) { return false; } final var missingVars = _this.uninstantiatedVars(); @@ -509,7 +504,6 @@ public static int hashCodeModProofIrrelevancy(TacletApp app) { EqualsModProofIrrelevancyUtil.hashCodeImmutableList(app.assumesFormulaInstantiations(), EqualityModuloProofIrrelevancy::hashCodeModProofIrrelevancy), app.instantiations(), - hashCodeModProofIrrelevancy(matchConditions), app.uninstantiatedVars(), app.isUpdateContextFixed(), app.rule()); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index b8482ee2d7..d496ae3586 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -60,14 +60,11 @@ public abstract class TacletApp implements RuleApp { private final /* @NonNull */ org.key_project.prover.rules.Taclet taclet; /** - * contains the instantiations of the schema variables of the Taclet - */ - protected final de.uka.ilkd.key.rule.inst.SVInstantiations instantiations; - - /** - * caches a created match condition {@code (instantiations, RenameTable.EMPTY)} + * match condition {@code (instantiations, RenameTable.EMPTY)} that contains the + * schemavariable to instantiations map + * */ - private final de.uka.ilkd.key.rule.MatchConditions matchConditions; + private final MatchConditions matchConditions; /** * chosen instantiations for the assumes-sequent formulas @@ -92,13 +89,13 @@ public abstract class TacletApp implements RuleApp { this(taclet, de.uka.ilkd.key.rule.inst.SVInstantiations.EMPTY_SVINSTANTIATIONS, null); } - TacletApp(org.key_project.prover.rules.Taclet taclet, SVInstantiations instantiations, + TacletApp(org.key_project.prover.rules.Taclet taclet, + SVInstantiations instantiations, ImmutableList assumesFormulaInstantiations) { this.taclet = taclet; - this.instantiations = (de.uka.ilkd.key.rule.inst.SVInstantiations) instantiations; this.assumesFormulaInstantiations = assumesFormulaInstantiations; - this.matchConditions = - new de.uka.ilkd.key.rule.MatchConditions(this.instantiations, RenameTable.EMPTY_TABLE); + this.matchConditions = new MatchConditions( + (de.uka.ilkd.key.rule.inst.SVInstantiations) instantiations, RenameTable.EMPTY_TABLE); } /** @@ -169,10 +166,10 @@ public Taclet rule() { * @return the SVInstantiations needed to instantiate the Taclet */ public de.uka.ilkd.key.rule.inst.SVInstantiations instantiations() { - return instantiations; + return matchConditions.getInstantiations(); } - public de.uka.ilkd.key.rule.MatchConditions matchConditions() { + public MatchConditions matchConditions() { return matchConditions; } @@ -284,11 +281,11 @@ protected static SVInstantiations replaceInstantiation( org.key_project.prover.rules.Taclet taclet, SVInstantiations insts, SchemaVariable varSV, Services services) { - JTerm term = getTermBelowQuantifier(taclet, varSV); - LogicVariable newVariable = new LogicVariable( - new Name(((JTerm) insts.getInstantiation(varSV)).op().name() + "0"), - ((JTerm) insts.getInstantiation(varSV)).sort()); + final Term instantiation = insts.getInstantiation(varSV); + final LogicVariable newVariable = new LogicVariable( + new Name(instantiation.op().name() + "0"), instantiation.sort()); // __CHANGE__ How to name the new variable? TODO + JTerm term = getTermBelowQuantifier(taclet, varSV); JTerm newVariableTerm = services.getTermBuilder().var(newVariable); return replaceInstantiation(insts, term, varSV, newVariableTerm, services); } @@ -301,10 +298,10 @@ private static de.uka.ilkd.key.rule.inst.SVInstantiations replaceInstantiation( SVInstantiations insts, JTerm t, SchemaVariable u, JTerm y, Services services) { var result = (de.uka.ilkd.key.rule.inst.SVInstantiations) insts; - LogicVariable x = (LogicVariable) ((JTerm) insts.getInstantiation(u)).op(); + final LogicVariable x = (LogicVariable) ((Term) insts.getInstantiation(u)).op(); if (t.op() instanceof SchemaVariable sv) { - if (!(t.op() instanceof VariableSV)) { - ClashFreeSubst cfSubst = new ClashFreeSubst(x, y, services.getTermBuilder()); + if (!(sv instanceof VariableSV)) { + final ClashFreeSubst cfSubst = new ClashFreeSubst(x, y, services.getTermBuilder()); result = result.replace(sv, cfSubst.apply(insts.getInstantiation(sv)), services); } @@ -344,13 +341,13 @@ public void checkApplicability() { public boolean isExecutable() { // bugfix #1336, see bugtracker if (taclet instanceof RewriteTaclet rwTaclet) { - ImmutableList oldUpdCtx = - matchConditions().getInstantiations().getUpdateContext(); var newConditions = rwTaclet.checkPrefix(posInOccurrence(), - de.uka.ilkd.key.rule.MatchConditions.EMPTY_MATCHCONDITIONS); + MatchConditions.EMPTY_MATCHCONDITIONS); if (newConditions == null) { return false; } + final ImmutableList oldUpdCtx = + matchConditions().getInstantiations().getUpdateContext(); final ImmutableList newUpdCtx = newConditions.getInstantiations().getUpdateContext(); return oldUpdCtx.equals(newUpdCtx); @@ -617,9 +614,11 @@ private TacletApp instantiationHelper(boolean force, Services services) { private Collection collectClashNames(SchemaVariable sv, TermServices services) { Collection result = new LinkedHashSet<>(); VariableCollectVisitor vcv = new VariableCollectVisitor(); + final de.uka.ilkd.key.rule.inst.SVInstantiations instantiations = + matchConditions.getInstantiations(); for (final var nv : taclet().varsNotFreeIn()) { if (nv.first() == sv) { - JTerm term = (JTerm) instantiations.getInstantiation(nv.second()); + JTerm term = instantiations.getInstantiation(nv.second()); if (term != null) { term.execPostOrder(vcv); } @@ -976,7 +975,8 @@ public boolean equals(Object o) { return false; } final TacletApp s = (TacletApp) o; - return (s.taclet.equals(taclet) && s.instantiations.equals(instantiations)) + return (s.taclet.equals(taclet) && + s.matchConditions.getInstantiations().equals(matchConditions.getInstantiations())) && (Objects.equals(assumesFormulaInstantiations, s.assumesFormulaInstantiations)); } @@ -984,7 +984,7 @@ public boolean equals(Object o) { public int hashCode() { int result = 17; result = 37 * result + taclet.hashCode(); - result = 37 * result + instantiations.hashCode(); + result = 37 * result + matchConditions.getInstantiations().hashCode(); result = 37 * result + (assumesFormulaInstantiations == null ? 0 : assumesFormulaInstantiations.hashCode()); return result; @@ -1060,6 +1060,7 @@ public TacletApp prepareUserInstantiation(Services services) { public Namespace<@NonNull Function> extendedFunctionNameSpace( Namespace<@NonNull Function> func_ns) { Namespace<@NonNull Function> ns = new Namespace<>(func_ns); + final var instantiations = matchConditions.getInstantiations(); for (var pair : instantiations.getInstantiationMap()) { if (pair.key() instanceof SkolemTermSV skolemSV) { JTerm inst = instantiations.getInstantiation(skolemSV); @@ -1092,7 +1093,7 @@ public SchemaVariable varSVNameConflict() { } } for (var varSV : prefix.prefix()) { - JTerm inst = (JTerm) instantiations().getInstantiation(varSV); + JTerm inst = instantiations().getInstantiation(varSV); if (inst != null) { Name name = inst.op().name(); if (!names.contains(name)) { From 0e8be5eafe9054de0a8d0d63501c4db8faa20301 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 17:55:28 +0200 Subject: [PATCH 12/62] Rewrite recursion to iterative solution (in this case the intend is clearer in the iterative one) and nullness annotations --- .../rule/EqualityModuloProofIrrelevancy.java | 3 +- .../de/uka/ilkd/key/rule/NoPosTacletApp.java | 12 ++---- .../key/rule/match/vm/VMTacletMatcher.java | 42 +++++++++---------- .../prover/rules/TacletMatcher.java | 9 +++- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java b/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java index 3b96fd18c1..daaef6ec02 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/EqualityModuloProofIrrelevancy.java @@ -499,7 +499,6 @@ public static boolean equalsModProofIrrelevancy(TacletApp _this, TacletApp that) * @return the hash code modulo proof irrelevancy for the given argument */ public static int hashCodeModProofIrrelevancy(TacletApp app) { - MatchConditions matchConditions = app.matchConditions(); return Objects.hash( EqualsModProofIrrelevancyUtil.hashCodeImmutableList(app.assumesFormulaInstantiations(), EqualityModuloProofIrrelevancy::hashCodeModProofIrrelevancy), @@ -567,7 +566,7 @@ public static boolean equalsModProofIrrelevancy(SVInstantiations _this, } } else if (inst instanceof ProgramElement instAsProgramElement) { if (!equalsModProofIrrelevancy(instAsProgramElement, - (ProgramElement) that.getInstantiation(e.key()))) { + that.getInstantiation(e.key()))) { return false; } } else if (!inst.equals(that.getInstantiation(e.key()))) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java index ed75b2cd9d..d493b1f195 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java @@ -247,11 +247,11 @@ private NoPosTacletApp matchFind(@Nullable JTerm termToBeMatched, PosInOccurrenc } MatchResultInfo res; - if (taclet() instanceof FindTaclet) { - res = taclet().getMatcher().matchFind(termToBeMatched, mc, services); + if (taclet() instanceof final FindTaclet findTaclet) { + res = findTaclet.getMatcher().matchFind(termToBeMatched, mc, services); // the following check will partly be repeated within the // constructor; this could be optimised - if (res == null || !checkVarCondNotFreeIn(taclet(), + if (res == null || !checkVarCondNotFreeIn(findTaclet, res.getInstantiations(), pos)) { return null; } @@ -268,10 +268,6 @@ private NoPosTacletApp evalCheckRes(MatchResultInfo res, Services services) { if (updateContextFixed && !updateContextCompatible((MatchConditions) res)) { - /* - * LOGGER.debug("NoPosTacletApp: Incompatible context", instantiations.getUpdateContext - * (), res.matchConditions().getInstantiations().getUpdateContext()); - */ return null; } @@ -299,7 +295,7 @@ protected MatchResultInfo setupMatchConditions(PosInOccurrence pos) { private boolean updateContextCompatible(MatchConditions p_mc) { - return instantiations.getUpdateContext() + return instantiations().getUpdateContext() .equals(p_mc.getInstantiations().getUpdateContext()); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java index 7f494303be..b38537be34 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java @@ -21,7 +21,6 @@ import org.key_project.logic.LogicServices; import org.key_project.logic.SyntaxElement; import org.key_project.logic.Term; -import org.key_project.logic.op.Operator; import org.key_project.logic.op.QuantifiableVariable; import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.*; @@ -38,6 +37,9 @@ import org.key_project.util.collection.ImmutableSet; import org.key_project.util.collection.Pair; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + import static de.uka.ilkd.key.logic.equality.RenamingTermProperty.RENAMING_TERM_PROPERTY; /** @@ -324,36 +326,31 @@ public final MatchResultInfo checkVariableConditions(SchemaVariable var, * and the find expression does not start with an update application operator * * @param source the term to be matched - * @param matchCond the accumulated match conditions for a successful match + * @param matchResult the accumulated match conditions for a successful match * @return a pair of updated match conditions and the unwrapped term without the ignored updates * (Which have been added to the update context in the match conditions) */ private Pair matchAndIgnoreUpdatePrefix( - final JTerm source, - final MatchResultInfo matchCond) { - final Operator sourceOp = source.op(); - - if (sourceOp instanceof UpdateApplication) { - // updates can be ignored - JTerm update = UpdateApplication.getUpdate(source); - final var svInstantiations = - ((MatchConditions) matchCond).getInstantiations(); - final var resultingConditions = - matchCond.setInstantiations(svInstantiations.addUpdate(update, source.getLabels())); - return matchAndIgnoreUpdatePrefix(UpdateApplication.getTarget(source), - resultingConditions); - } else { - return new Pair<>(source, matchCond); + JTerm source, final MatchResultInfo matchResult) { + final MatchConditions matchCond = (MatchConditions) matchResult; + final var instantiations = matchCond.getInstantiations(); + ImmutableList updateLabel = instantiations.getUpdateContext(); + while (source.op() instanceof UpdateApplication) { + final JTerm update = UpdateApplication.getUpdate(source); + updateLabel = updateLabel.append(new UpdateLabelPair(update, source.getLabels())); + source = UpdateApplication.getTarget(source); } + return new Pair<>(source, + matchCond.setInstantiations(instantiations.addUpdateList(updateLabel))); } /** * {@inheritDoc} */ @Override - public final MatchResultInfo matchFind( - Term term, - MatchResultInfo p_matchCond, + public final @Nullable MatchResultInfo matchFind( + @NonNull Term term, + @NonNull MatchResultInfo p_matchCond, LogicServices services) { if (findMatchProgram == null) { return null; @@ -365,9 +362,8 @@ public final MatchResultInfo matchFind( source = resultUpdateMatch.first; p_matchCond = resultUpdateMatch.second; } - return checkConditions( - findMatchProgram.match(source, p_matchCond, services), - services); + final MatchResultInfo matchResult = findMatchProgram.match(source, p_matchCond, services); + return matchResult == null ? null : checkConditions(matchResult, services); } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java index 1d2ea60b9f..704fd99ab3 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java @@ -11,6 +11,9 @@ import org.key_project.prover.rules.instantiation.AssumesMatchResult; import org.key_project.prover.rules.instantiation.MatchResultInfo; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + public interface TacletMatcher { /** * matches the given term against the taclet's find term if the taclet has no find term or the @@ -28,8 +31,10 @@ public interface TacletMatcher { * @param services the Services * @return the found schema variable mapping or null if the matching failed */ - MatchResultInfo matchFind(Term term, MatchResultInfo matchCond, - LogicServices services); + @Nullable + MatchResultInfo matchFind(@NonNull Term term, + @NonNull MatchResultInfo matchCond, + @Nullable LogicServices services); /** * checks if the conditions for a correct instantiation are satisfied From 5baa6662e922e4a40c5f3d78655dbdc03e4cf521 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 13 Jun 2025 18:18:56 +0200 Subject: [PATCH 13/62] Nullness fixes and removal of unnecessary casts --- .../SimplifyIfThenElseUpdateCondition.java | 13 +++-- .../key/rule/match/vm/VMTacletMatcher.java | 47 ++++++++++--------- .../prover/rules/TacletMatcher.java | 18 ++++--- .../prover/rules/VariableCondition.java | 8 +++- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/SimplifyIfThenElseUpdateCondition.java b/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/SimplifyIfThenElseUpdateCondition.java index fdc45e3fa5..9388884f6b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/SimplifyIfThenElseUpdateCondition.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/SimplifyIfThenElseUpdateCondition.java @@ -156,16 +156,15 @@ private JTerm simplify(JTerm phi, JTerm u1, JTerm u2, JTerm t, TermServices serv @Override public MatchResultInfo check(SchemaVariable var, SyntaxElement instCandidate, - MatchResultInfo mc, - LogicServices p_services) { + MatchResultInfo mc, LogicServices p_services) { final Services services = (Services) p_services; SVInstantiations svInst = mc.getInstantiations(); - JTerm u1Inst = (JTerm) svInst.getInstantiation(u1); - JTerm u2Inst = (JTerm) svInst.getInstantiation(u2); - JTerm tInst = (JTerm) svInst.getInstantiation(commonFormula); - JTerm phiInst = (JTerm) svInst.getInstantiation(phi); - JTerm resultInst = (JTerm) svInst.getInstantiation(result); + JTerm u1Inst = svInst.getInstantiation(u1); + JTerm u2Inst = svInst.getInstantiation(u2); + JTerm tInst = svInst.getInstantiation(commonFormula); + JTerm phiInst = svInst.getInstantiation(phi); + JTerm resultInst = svInst.getInstantiation(result); if (tInst == null || phiInst == null) { return mc; diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java index b38537be34..150da7e111 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java @@ -121,10 +121,11 @@ public VMTacletMatcher(Taclet taclet) { * LogicServices) */ @Override - public final AssumesMatchResult matchAssumes(Iterable p_toMatch, - Term p_template, - MatchResultInfo p_matchCond, - LogicServices p_services) { + public final @NonNull AssumesMatchResult matchAssumes( + @NonNull Iterable<@NonNull AssumesFormulaInstantiation> p_toMatch, + @NonNull Term p_template, + @NonNull MatchResultInfo p_matchCond, + @NonNull LogicServices p_services) { VMProgramInterpreter interpreter = assumesMatchPrograms.get(p_template); final var mc = (MatchConditions) p_matchCond; @@ -240,15 +241,18 @@ public final MatchResultInfo matchAssumes( * {@inheritDoc} */ @Override - public final MatchResultInfo checkConditions( - MatchResultInfo cond, - LogicServices services) { + public final @Nullable MatchResultInfo checkConditions( + @Nullable MatchResultInfo cond, + @NonNull LogicServices services) { var result = (MatchConditions) cond; if (result != null) { final var svIterator = result.getInstantiations().svIterator(); if (!svIterator.hasNext()) { + // for example SimplifyIfThenElseUpdateCondition + // rewrite these conditions and avoid null; conditions that do not involve matched + // variables return checkVariableConditions(null, null, cond, services);// XXX } @@ -256,8 +260,7 @@ public final MatchResultInfo checkConditions( final SchemaVariable sv = svIterator.next(); final Object o = result.getInstantiations().getInstantiation(sv); if (o instanceof SyntaxElement se) { - result = (MatchConditions) checkVariableConditions(sv, se, - result, services); + result = (MatchConditions) checkVariableConditions(sv, se, result, services); } } } @@ -295,17 +298,16 @@ private boolean varIsBound(SchemaVariable v) { * {@inheritDoc} */ @Override - public final MatchResultInfo checkVariableConditions(SchemaVariable var, - SyntaxElement instantiationCandidate, - MatchResultInfo matchCond, - LogicServices services) { + public final @Nullable MatchResultInfo checkVariableConditions(@Nullable SchemaVariable var, + @Nullable SyntaxElement instantiationCandidate, + @Nullable MatchResultInfo matchCond, + @NonNull LogicServices services) { if (matchCond != null) { if (instantiationCandidate instanceof JTerm term) { if (!(term.op() instanceof QuantifiableVariable)) { if (varIsBound(var) || varDeclaredNotFree(var)) { // match(x) is not a variable, but the corresponding template variable is - // bound - // or declared non free (so it has to be matched to a variable) + // bound or declared non free (so it has to be matched to a variable) return null; // FAILED } } @@ -371,19 +373,18 @@ private Pair matchAndIgnoreUpdatePrefix( * {@inheritDoc} */ @Override - public MatchResultInfo matchSV(SchemaVariable sv, - SyntaxElement syntaxElement, - MatchResultInfo matchCond, - LogicServices services) { + public @Nullable MatchResultInfo matchSV(@NonNull SchemaVariable sv, + @NonNull SyntaxElement syntaxElement, + @NonNull MatchResultInfo matchCond, + @NonNull LogicServices services) { final MatchSchemaVariableInstruction instr = JavaDLMatchVMInstructionSet.getMatchInstructionForSV(sv); - if (syntaxElement instanceof JTerm term) { - matchCond = instr.match(term, matchCond, services); + matchCond = instr.match(syntaxElement, matchCond, services); + if (syntaxElement instanceof JTerm) { matchCond = checkVariableConditions(sv, syntaxElement, matchCond, services); - } else if (syntaxElement instanceof ProgramElement pe) { - matchCond = instr.match(pe, (MatchConditions) matchCond, services); + } else if (syntaxElement instanceof ProgramElement) { matchCond = checkConditions(matchCond, services); } return matchCond; diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java index 704fd99ab3..d7a57024d2 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java @@ -47,9 +47,11 @@ MatchResultInfo matchFind(@NonNull Term term, * @return the match conditions resulting from matching var with * instantiationCandidate or null if a match was not possible */ - MatchResultInfo checkVariableConditions(org.key_project.logic.op.sv.SchemaVariable var, - SyntaxElement instantiationCandidate, MatchResultInfo matchCond, - LogicServices services); + @Nullable + MatchResultInfo checkVariableConditions( + org.key_project.logic.op.sv.@Nullable SchemaVariable var, + @Nullable SyntaxElement instantiationCandidate, @Nullable MatchResultInfo matchCond, + @NonNull LogicServices services); /** * checks the provided matches against the variable conditions of this taclet It returns the @@ -62,7 +64,9 @@ MatchResultInfo checkVariableConditions(org.key_project.logic.op.sv.SchemaVariab * @return the resulting match conditions or null if given matches do not satisfy * the taclet's variable conditions */ - MatchResultInfo checkConditions(MatchResultInfo matchResultInfo, LogicServices services); + @Nullable + MatchResultInfo checkConditions(@Nullable MatchResultInfo matchResultInfo, + @NonNull LogicServices services); /** * Match the given template (which is probably a formula of the assumes-sequent) against a list @@ -80,8 +84,10 @@ MatchResultInfo checkVariableConditions(org.key_project.logic.op.sv.SchemaVariab * could successfully be matched against p_template, and the corresponding * MatchConditions. */ - AssumesMatchResult matchAssumes(Iterable toMatch, Term template, - MatchResultInfo matchCond, LogicServices services); + @NonNull + AssumesMatchResult matchAssumes(@NonNull Iterable<@NonNull AssumesFormulaInstantiation> toMatch, + @NonNull Term template, @NonNull MatchResultInfo matchCond, + @NonNull LogicServices services); /** * Match the whole if sequent using the given list of instantiations of all assumes-sequent diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/VariableCondition.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/VariableCondition.java index 7269248a0d..46959330ec 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/VariableCondition.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/VariableCondition.java @@ -8,6 +8,9 @@ import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.instantiation.MatchResultInfo; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; + /// The instantiations of a schema variable can be restricted on rule scope by attaching conditions /// on these variables. Such a condition is realized by a class which implements this interface. /// @@ -23,6 +26,7 @@ public interface VariableCondition { /// @param services the logic and program information object /// @return modified match results if the condition can be satisfied, or `null` /// otherwise - MatchResultInfo check(SchemaVariable var, SyntaxElement instCandidate, - MatchResultInfo matchCond, LogicServices services); + @Nullable + MatchResultInfo check(@Nullable SchemaVariable var, @Nullable SyntaxElement instCandidate, + @NonNull MatchResultInfo matchCond, @NonNull LogicServices services); } From 48c4621c7a326450cf98ac9a56103e04d76bd8c8 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 14 Jun 2025 11:57:41 +0200 Subject: [PATCH 14/62] Nullness annotations --- .../java/de/uka/ilkd/key/rule/TacletApp.java | 6 ++--- .../ilkd/key/rule/inst/SVInstantiations.java | 3 ++- .../key/rule/match/vm/VMTacletMatcher.java | 25 ++++++++++--------- .../prover/rules/TacletMatcher.java | 8 +++--- .../instantiation/AssumesMatchResult.java | 6 +++-- .../exploration/ProofExplorationService.java | 2 +- 6 files changed, 28 insertions(+), 22 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index d496ae3586..88febef85f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -64,7 +64,7 @@ public abstract class TacletApp implements RuleApp { * schemavariable to instantiations map * */ - private final MatchConditions matchConditions; + private final @NonNull MatchConditions matchConditions; /** * chosen instantiations for the assumes-sequent formulas @@ -156,7 +156,7 @@ public Taclet taclet() { * @return the Rule the application information is collected for */ @Override - public Taclet rule() { + public @NonNull Taclet rule() { return (Taclet) taclet; } @@ -169,7 +169,7 @@ public de.uka.ilkd.key.rule.inst.SVInstantiations instantiations() { return matchConditions.getInstantiations(); } - public MatchConditions matchConditions() { + public @NonNull MatchConditions matchConditions() { return matchConditions; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java index 840bccface..f641e315bc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java @@ -619,6 +619,7 @@ public String toString() { return e == null ? null : (T) e.value().getInstantiation(); } - public record UpdateLabelPair(JTerm update, ImmutableArray updateApplicationlabels) { + public record UpdateLabelPair(@NonNull JTerm update, + ImmutableArray updateApplicationlabels) { } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java index 150da7e111..6c7c24996d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java @@ -59,7 +59,8 @@ public class VMTacletMatcher implements TacletMatcher { /** the matcher for the find expression of the taclet */ private final VMProgramInterpreter findMatchProgram; /** the matcher for the taclet's assumes formulas */ - private final HashMap assumesMatchPrograms = new HashMap<>(); + private final HashMap assumesMatchPrograms = + new HashMap<>(); /** * the variable conditions of the taclet that need to be satisfied by found schema variable @@ -94,8 +95,8 @@ public VMTacletMatcher(Taclet taclet) { boundVars = taclet.getBoundVariables(); varsNotFreeIn = taclet.varsNotFreeIn(); - if (taclet instanceof FindTaclet) { - findExp = ((FindTaclet) taclet).find(); + if (taclet instanceof final FindTaclet findTaclet) { + findExp = findTaclet.find(); ignoreTopLevelUpdates = taclet.ignoreTopLevelUpdates() && !(findExp.op() instanceof UpdateApplication); findMatchProgram = @@ -107,8 +108,8 @@ public VMTacletMatcher(Taclet taclet) { findMatchProgram = null; } - for (SequentFormula sf : assumesSequent) { - assumesMatchPrograms.put((JTerm) sf.formula(), + for (final SequentFormula sf : assumesSequent) { + assumesMatchPrograms.put(sf.formula(), new VMProgramInterpreter( SyntaxElementMatchProgramGenerator.createProgram((JTerm) sf.formula()))); } @@ -194,10 +195,10 @@ private JTerm matchUpdateContext(ImmutableList context, JTerm f * @see TacletMatcher#matchAssumes(Iterable, MatchResultInfo, LogicServices) */ @Override - public final MatchResultInfo matchAssumes( - Iterable p_toMatch, - MatchResultInfo p_matchCond, - LogicServices p_services) { + public final @Nullable MatchResultInfo matchAssumes( + @NonNull Iterable p_toMatch, + @NonNull MatchResultInfo p_matchCond, + @NonNull LogicServices p_services) { final Iterator anteIterator = assumesSequent.antecedent().iterator(); final Iterator succIterator = assumesSequent.succedent().iterator(); @@ -207,8 +208,8 @@ public final MatchResultInfo matchAssumes( for (final AssumesFormulaInstantiation candidateInst : p_toMatch) { // Part of fix for #1716: match antecedent with antecedent, succ with succ boolean candidateInAntec = - (candidateInst instanceof AssumesFormulaInstSeq candidateInSeq) - // Only IfFormulaInstSeq has inAntec() property ... + (candidateInst instanceof final AssumesFormulaInstSeq candidateInSeq) + // Only if AssumesFormulaInstSeq has inAntec() property ... && (candidateInSeq.inAntecedent()) || !(candidateInst instanceof AssumesFormulaInstSeq) // ... and it seems we don't need the check for other @@ -353,7 +354,7 @@ private Pair matchAndIgnoreUpdatePrefix( public final @Nullable MatchResultInfo matchFind( @NonNull Term term, @NonNull MatchResultInfo p_matchCond, - LogicServices services) { + @NonNull LogicServices services) { if (findMatchProgram == null) { return null; } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java index d7a57024d2..5e84826266 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java @@ -34,7 +34,7 @@ public interface TacletMatcher { @Nullable MatchResultInfo matchFind(@NonNull Term term, @NonNull MatchResultInfo matchCond, - @Nullable LogicServices services); + @NonNull LogicServices services); /** * checks if the conditions for a correct instantiation are satisfied @@ -99,9 +99,11 @@ AssumesMatchResult matchAssumes(@NonNull Iterable<@NonNull AssumesFormulaInstant * * @return resulting MatchConditions or null if the given list p_toMatch does not match */ - MatchResultInfo matchAssumes(Iterable toMatch, - MatchResultInfo matchCond, LogicServices services); + @Nullable + MatchResultInfo matchAssumes(@NonNull Iterable toMatch, + @NonNull MatchResultInfo matchCond, @NonNull LogicServices services); + @Nullable MatchResultInfo matchSV(SchemaVariable sv, SyntaxElement se, MatchResultInfo matchResultInfo, LogicServices services); } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java index 2e21cc4da5..1c67712949 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java @@ -5,6 +5,8 @@ import org.key_project.util.collection.ImmutableList; +import org.jspecify.annotations.NonNull; + /// /// There can be several candidates for matching a formula of an assumes clause of a taclet. This /// record @@ -29,6 +31,6 @@ /// /// @param candidates the list of candidate instantiations /// @param matchConditions the list of match conditions -public record AssumesMatchResult(ImmutableList candidates, - ImmutableList matchConditions) { +public record AssumesMatchResult(ImmutableList<@NonNull AssumesFormulaInstantiation> candidates, + ImmutableList<@NonNull MatchResultInfo> matchConditions) { } diff --git a/keyext.exploration/src/main/java/org/key_project/exploration/ProofExplorationService.java b/keyext.exploration/src/main/java/org/key_project/exploration/ProofExplorationService.java index 36ef907561..91ecdfe1ed 100644 --- a/keyext.exploration/src/main/java/org/key_project/exploration/ProofExplorationService.java +++ b/keyext.exploration/src/main/java/org/key_project/exploration/ProofExplorationService.java @@ -168,7 +168,7 @@ public Node applyChangeFormula(@NonNull Goal g, FindTaclet tap = getHideTaclet(pio.isInAntec()); TacletApp weakening = PosTacletApp.createPosTacletApp(tap, tap.getMatcher().matchFind(pio.subTerm(), MatchConditions.EMPTY_MATCHCONDITIONS, - null), + services), pio, services); String posToWeakening = pio.isInAntec() ? "TRUE" : "FALSE"; From ee40d81e11307a69d79597db7f4ee2ae81ae15cd Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 14 Jun 2025 12:14:01 +0200 Subject: [PATCH 15/62] Added and updated comments --- .../prover/rules/TacletMatcher.java | 103 +++++++++--------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java index 5e84826266..07d9186ae0 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/TacletMatcher.java @@ -14,22 +14,22 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +/** + * Defines the interface for matching terms against the pattern (find) part of a taclet, + * handling schema variable instantiations and checking variable conditions. + */ public interface TacletMatcher { + /** - * matches the given term against the taclet's find term if the taclet has no find term or the - * match is unsuccessful null - * is returned - * - * @param term the Term to be matched against the find expression - * of the taclet - * @param matchCond the MatchConditions with side conditions to be - * satisfied, e.g. partial instantiations of schema variables; before - * calling this method the constraint contained in the match conditions - * must be ensured to be satisfiable, i.e. - * {@code matchCond.getConstraint().isSatisfiable()} must return true + * Attempts to match the given term against the taclet's "find" term. + *

+ * If the taclet has no "find" term, or if matching fails, this method returns {@code null}. * - * @param services the Services - * @return the found schema variable mapping or null if the matching failed + * @param term the {@link Term} to be matched against the taclet's "find" expression + * @param matchCond the current {@link MatchResultInfo} including partial instantiations + * @param services the {@link LogicServices} providing contextual information + * @return the updated match result (possibly with added schema variable instantiations) on + * success, or {@code null} if no match is found */ @Nullable MatchResultInfo matchFind(@NonNull Term term, @@ -37,15 +37,14 @@ MatchResultInfo matchFind(@NonNull Term term, @NonNull LogicServices services); /** - * checks if the conditions for a correct instantiation are satisfied + * Checks whether a schema variable can be instantiated with the given candidate term, + * under the provided match conditions. * - * @param var the SchemaVariable to be instantiated - * @param instantiationCandidate the SVSubstitute, which is a candidate for a possible - * instantiation of var - * @param matchCond the MatchConditions which have to be respected for the new match - * @param services the Services object encapsulating information about the Rust type model - * @return the match conditions resulting from matching var with - * instantiationCandidate or null if a match was not possible + * @param var the {@link SchemaVariable} to instantiate + * @param instantiationCandidate the candidate instantiation for {@code var} + * @param matchCond the current {@link MatchResultInfo} representing the current match status + * @param services the {@link LogicServices} providing contextual information + * @return the updated match result if instantiation is valid, or {@code null} otherwise */ @Nullable MatchResultInfo checkVariableConditions( @@ -54,35 +53,31 @@ MatchResultInfo checkVariableConditions( @NonNull LogicServices services); /** - * checks the provided matches against the variable conditions of this taclet It returns the - * resulting match conditions or null if the found matches do not satisfy the - * variable conditions. If the given matchconditions are null then - * null is returned + * Checks the given match result against the taclet's variable conditions. + *

+ * Returns an updated match result if all conditions are satisfied. If not, or if + * {@code matchResultInfo} is {@code null}, the method returns {@code null}. * - * @param matchResultInfo the matches to be checked - * @param services the {@link LogicServices} - * @return the resulting match conditions or null if given matches do not satisfy - * the taclet's variable conditions + * @param matchResultInfo the match result to validate + * @param services the {@link LogicServices} providing contextual information + * @return the validated and potentially updated match result, or {@code null} if validation + * fails */ @Nullable MatchResultInfo checkConditions(@Nullable MatchResultInfo matchResultInfo, @NonNull LogicServices services); /** - * Match the given template (which is probably a formula of the assumes-sequent) against a list - * of - * constraint formulas (probably the formulas of the antecedent or the succedent), starting with - * the given instantiations and constraint {@code p_matchCond}. + * Matches a template formula (typically from the "assumes" part of a taclet) against a + * list of constraint formulas (e.g., from a sequent's antecedent or succedent), + * using the given initial match conditions. * - * @param toMatch list of constraint formulas to match p_template to - * @param template template formula as in "match" - * @param matchCond already performed instantiations - * @param services the Services object encapsulating information about the Rust datastructures - * like (static)types etc. - * @return Two lists (in an {@link AssumesMatchResult} object), containing the elements of - * {@code p_toMatch} that - * could successfully be matched against p_template, and the corresponding - * MatchConditions. + * @param toMatch a list of formulas to attempt matching with {@code template} + * @param template the formula template to match against each formula in {@code toMatch} + * @param matchCond the current {@link MatchResultInfo} representing the current match status + * @param services the {@link LogicServices} providing contextual information + * @return a result containing the successfully matched formulas and their associated match + * conditions */ @NonNull AssumesMatchResult matchAssumes(@NonNull Iterable<@NonNull AssumesFormulaInstantiation> toMatch, @@ -90,20 +85,30 @@ AssumesMatchResult matchAssumes(@NonNull Iterable<@NonNull AssumesFormulaInstant @NonNull LogicServices services); /** - * Match the whole if sequent using the given list of instantiations of all assumes-sequent - * formulas, - * starting with the instantiations given by p_matchCond. + * Matches a list of formula instantiations against the full "assumes" sequent of a taclet, + * starting with the given initial match conditions. *

- * PRECONDITION: {@code p_toMatch.size () == ifSequent().size()} - *

+ * Precondition: {@code toMatch.size() == ifSequent().size()} * - * @return resulting MatchConditions or null if the given list p_toMatch does not match + * @param toMatch a list of formulas to attempt matching with {@code template} + * @param matchCond the current {@link MatchResultInfo} representing the current match status + * @param services the {@link LogicServices} providing contextual information + * @return the resulting match conditions if successful; {@code null} otherwise */ @Nullable MatchResultInfo matchAssumes(@NonNull Iterable toMatch, @NonNull MatchResultInfo matchCond, @NonNull LogicServices services); + /** + * Matches a schema variable to a syntax element under the given match conditions. + * + * @param sv the {@link SchemaVariable} to match + * @param se the candidate {@link SyntaxElement} + * @param matchCond the current {@link MatchResultInfo} representing the current match status + * @param services the {@link LogicServices} providing contextual information + * @return updated match result if successful; {@code null} if no match was possible + */ @Nullable - MatchResultInfo matchSV(SchemaVariable sv, SyntaxElement se, MatchResultInfo matchResultInfo, + MatchResultInfo matchSV(SchemaVariable sv, SyntaxElement se, MatchResultInfo matchCond, LogicServices services); } From a65e4b08c7297371e9e29b1cbde3ccd340e37359 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sun, 15 Jun 2025 11:45:53 +0200 Subject: [PATCH 16/62] Cleanup TacletApp (and subclasses) --- .../de/uka/ilkd/key/rule/NoPosTacletApp.java | 10 ++-- .../de/uka/ilkd/key/rule/PosTacletApp.java | 46 +++++++++---------- .../java/de/uka/ilkd/key/rule/TacletApp.java | 39 ++++++---------- .../prover/indexing/FormulaTagManager.java | 3 +- .../instantiation/AssumesMatchResult.java | 21 +++------ 5 files changed, 49 insertions(+), 70 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java index d493b1f195..a9c311b91e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/NoPosTacletApp.java @@ -4,6 +4,9 @@ package de.uka.ilkd.key.rule; +import java.util.Collections; +import java.util.Set; + import de.uka.ilkd.key.java.ProgramElement; import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.JTerm; @@ -19,9 +22,7 @@ import org.key_project.prover.rules.instantiation.MatchResultInfo; import org.key_project.prover.rules.instantiation.SVInstantiations; import org.key_project.prover.sequent.PosInOccurrence; -import org.key_project.util.collection.DefaultImmutableSet; import org.key_project.util.collection.ImmutableList; -import org.key_project.util.collection.ImmutableSet; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -198,8 +199,8 @@ protected TacletApp setAllInstantiations(MatchResultInfo mc, } @Override - protected ImmutableSet contextVars(SchemaVariable sv) { - return DefaultImmutableSet.nil(); + protected Set contextVars(SchemaVariable sv) { + return Collections.emptySet(); } /** @@ -293,7 +294,6 @@ protected MatchResultInfo setupMatchConditions(PosInOccurrence pos) { return mc; } - private boolean updateContextCompatible(MatchConditions p_mc) { return instantiations().getUpdateContext() .equals(p_mc.getInstantiations().getUpdateContext()); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java index 2f5680f22b..87b63623f9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/PosTacletApp.java @@ -3,11 +3,11 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.rule; -import java.util.Iterator; +import java.util.Collections; +import java.util.Set; import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.JTerm; -import de.uka.ilkd.key.util.Debug; import org.key_project.logic.LogicServices; import org.key_project.logic.SyntaxElement; @@ -18,9 +18,7 @@ import org.key_project.prover.rules.instantiation.MatchResultInfo; import org.key_project.prover.rules.instantiation.SVInstantiations; import org.key_project.prover.sequent.PosInOccurrence; -import org.key_project.util.collection.DefaultImmutableSet; import org.key_project.util.collection.ImmutableList; -import org.key_project.util.collection.ImmutableSet; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -60,9 +58,8 @@ public static PosTacletApp createPosTacletApp(FindTaclet taclet, SVInstantiations instantiations, ImmutableList assumesInstantiations, PosInOccurrence pos, Services services) { - Debug.assertTrue(ifInstsCorrectSize(taclet, assumesInstantiations), - "If instantiations list has wrong size"); - + assert ifInstsCorrectSize(taclet, assumesInstantiations) + : "If instantiations list has wrong size"; instantiations = resolveCollisionWithContext(taclet, resolveCollisionVarSV(taclet, instantiations, services), pos, services); if (checkVarCondNotFreeIn(taclet, instantiations, pos)) { @@ -91,7 +88,6 @@ private PosTacletApp(FindTaclet taclet, SVInstantiations instantiations, this.pos = pos; } - /** * returns the LogicVariables that are bound above the PositionInOccurrence of the PosTacletApp. * __OPTIMIZE__ If this method is needed more than once caching the result should be considered. @@ -99,31 +95,31 @@ private PosTacletApp(FindTaclet taclet, SVInstantiations instantiations, * @return the set of the logicvariables that are bound for the indicated application position * of the TacletApp. */ - private static ImmutableSet varsBoundAboveFindPos(Taclet taclet, + private static Set varsBoundAboveFindPos(Taclet taclet, PosInOccurrence pos) { - - if (!(taclet instanceof RewriteTaclet)) { - return DefaultImmutableSet.nil(); + if (taclet instanceof RewriteTaclet) { + return collectBoundVarsAbove(pos); + } else { + return Collections.emptySet(); } - - return collectBoundVarsAbove(pos); } - private static Iterator allVariableSV(Taclet taclet) { + private static Iterable allVariableSV(Taclet taclet) { TacletVariableSVCollector coll = new TacletVariableSVCollector(); coll.visit(taclet, true); // __CHANGE__ true or false??? - return coll.varIterator(); + return coll.vars(); } @Override - protected ImmutableSet contextVars(SchemaVariable sv) { + protected Set contextVars(SchemaVariable sv) { final TacletPrefix prefix = taclet().getPrefix(sv); assert prefix != null : "prefix should not be null for taclets with a find"; - if (!prefix.context()) { - return DefaultImmutableSet.nil(); + if (prefix.context()) { + return varsBoundAboveFindPos(taclet(), posInOccurrence()); + } else { + return Collections.emptySet(); } - return varsBoundAboveFindPos(taclet(), posInOccurrence()); } @@ -137,11 +133,11 @@ private static SVInstantiations resolveCollisionWithContext(Taclet taclet, SVInstantiations insts, PosInOccurrence pos, Services services) { if (taclet.isContextInPrefix()) { - ImmutableSet k = varsBoundAboveFindPos(taclet, pos); - Iterator it = allVariableSV(taclet); - while (it.hasNext()) { - SchemaVariable varSV = it.next(); - JTerm inst = insts.getInstantiation(varSV); + Set k = varsBoundAboveFindPos(taclet, pos); + for (var varSV : allVariableSV(taclet)) { + final JTerm inst = insts.getInstantiation(varSV); + // if inst != null then inst.op() must be a QuantifiableVAriable + // as we look only at VariableSVs if (inst != null && k.contains(inst.op())) { insts = replaceInstantiation(taclet, insts, varSV, services); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java index 88febef85f..9898de0aba 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/TacletApp.java @@ -5,6 +5,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Predicate; import de.uka.ilkd.key.java.*; import de.uka.ilkd.key.java.abstraction.KeYJavaType; @@ -106,14 +107,14 @@ public abstract class TacletApp implements RuleApp { * @param pos the posInOccurrence describing the position of the schemavariable * @return set of the bound variables */ - protected static ImmutableSet boundAtOccurrenceSet(TacletPrefix prefix, + protected static Set boundAtOccurrenceSet(TacletPrefix prefix, SVInstantiations instantiations, @Nullable PosInOccurrence pos) { - ImmutableSet result = + Set result = collectPrefixInstantiations(prefix, instantiations); if (pos != null && prefix.context()) { - result = result.union(collectBoundVarsAbove(pos)); + result.addAll(collectBoundVarsAbove(pos)); } return result; @@ -127,14 +128,14 @@ protected static ImmutableSet boundAtOccurrenceSet(TacletP * @return the set of the logic variables whose elements are the instantiations of a bound * SchemaVariable appearing in the TacletPrefix */ - private static ImmutableSet collectPrefixInstantiations(TacletPrefix pre, + private static Set collectPrefixInstantiations(TacletPrefix pre, SVInstantiations instantiations) { - ImmutableSet instanceSet = DefaultImmutableSet.nil(); + LinkedHashSet instanceSet = new LinkedHashSet<>(); for (final var prefixSchemaVar : pre.prefix()) { - instanceSet = instanceSet.add( - (LogicVariable) ((JTerm) instantiations.getInstantiation(prefixSchemaVar)).op()); + instanceSet.add( + (LogicVariable) instantiations.getInstantiation(prefixSchemaVar).op()); } return instanceSet; } @@ -1016,7 +1017,7 @@ public TacletApp prepareUserInstantiation(Services services) { return result; } - protected abstract ImmutableSet contextVars(SchemaVariable sv); + protected abstract Set contextVars(SchemaVariable sv); /** * creates a new variable namespace by adding names of the instantiations of the schema @@ -1042,9 +1043,7 @@ public TacletApp prepareUserInstantiation(Services services) { } } if (tacletPrefix.context()) { - for (final QuantifiableVariable quantifiableVariable : contextVars(sv)) { - ns.add(quantifiableVariable); - } + ns.add(contextVars(sv)); } return ns; } @@ -1197,14 +1196,13 @@ protected static boolean checkVarCondNotFreeIn(org.key_project.prover.rules.Tacl continue; } - final ImmutableSet boundVarSet = + final Set boundVarSet = boundAtOccurrenceSet((TacletPrefix) prefix, instantiations, pos); final Term inst = instantiations.getInstantiation(sv); - if (!inst.freeVars().subset(boundVarSet)) { + if (inst.freeVars().exists(Predicate.not(boundVarSet::contains))) { return false; } } - return true; } @@ -1215,21 +1213,14 @@ protected static boolean checkVarCondNotFreeIn(org.key_project.prover.rules.Tacl * @param pos the PosInOccurrence describing a subterm in Term * @return a set of logic variables that are bound above the specified subterm */ - protected static ImmutableSet collectBoundVarsAbove( + protected static Set collectBoundVarsAbove( PosInOccurrence pos) { - ImmutableSet result = DefaultImmutableSet.nil(); - + LinkedHashSet result = new LinkedHashSet<>(); PIOPathIterator it = pos.iterator(); int i; - ImmutableArray vars; - while ((i = it.next()) != -1) { - vars = (ImmutableArray) it.getSubTerm().varsBoundHere(i); - for (i = 0; i < vars.size(); i++) { - result = result.add(vars.get(i)); - } + it.getSubTerm().varsBoundHere(i).forEach(result::add); } - return result; } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java index 89f65a5274..dab030d35c 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/FormulaTagManager.java @@ -82,6 +82,7 @@ public long getAgeForTag(FormulaTag p_tag) { * * @return All modifications that were applied to the formula with the given tag since the * creation of the tag, starting with the most recent one + * @throws NullPointerException if the provided tag is not managed by this manager */ public ImmutableList<@NonNull FormulaChangeInfo> getModifications(FormulaTag p_tag) { final FormulaInfo formulaInfo = getFormulaInfo(p_tag); @@ -149,7 +150,7 @@ private void createNewTags(ProofGoal p_goal) { * Create new tags for all formulas of a semisequent * * @param semisequent the {@link Semisequent} for which to create the tags - * @param newAge the long indicating the age of the {@link ProofGoal} to which the semisequent + * @param newAge a long indicating the age of the {@link ProofGoal} to which the semisequent * belongs * @param p_antec true iff the semisequent is an antecedent */ diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java index 1c67712949..a1c1476591 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/instantiation/AssumesMatchResult.java @@ -9,25 +9,16 @@ /// /// There can be several candidates for matching a formula of an assumes clause of a taclet. This -/// record -/// keeps for a given formula the list of successful instantiations for the sequent formula as well -/// as -/// their corresponding math results (match conditions) that break down the candidate formula to -/// instantiations -/// of the schema variables that made up the assumes-formula. -/// +/// record keeps for a given formula the list of successful instantiations for the sequent formula +/// as well as their corresponding math results (match conditions) that break down the candidate +/// formula to instantiations of the schema variables that made up the assumes-formula. /// /// It is not sufficient to simply keep the match conditions as for the taclet application itself -/// the -/// candidate information is used to decide whether to split the goal or not. See -/// [AssumesFormulaInstantiation] -/// and subclasses for more details. -/// +/// the candidate information is used to decide whether to split the goal or not. +/// See [AssumesFormulaInstantiation] and subclasses for more details. /// /// The two lists are paired in the sense that the match conditions for the i-th candidate can be -/// found at -/// the i-th position of list `matchConditions`. -/// +/// found at the i-th position of list `matchConditions`. /// /// @param candidates the list of candidate instantiations /// @param matchConditions the list of match conditions From a79aba3bd324672eb81771de06ce652482a6daf7 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 3 Jul 2025 09:39:58 +0200 Subject: [PATCH 17/62] Move RuleIndex to ncore --- key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java | 4 ++++ .../main/java/org/key_project/prover/indexing}/RuleIndex.java | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) rename {key.core/src/main/java/de/uka/ilkd/key/proof => key.ncore.calculus/src/main/java/org/key_project/prover/indexing}/RuleIndex.java (98%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java b/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java index 45fd8bd0fe..b50940b9d3 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/TacletIndex.java @@ -21,6 +21,7 @@ import org.key_project.logic.op.Operator; import org.key_project.logic.op.sv.OperatorSV; import org.key_project.logic.op.sv.SchemaVariable; +import org.key_project.prover.indexing.RuleIndex; import org.key_project.prover.proof.rulefilter.RuleFilter; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.util.collection.DefaultImmutableSet; @@ -541,6 +542,9 @@ public String toString() { """.formatted(antecList, succList, rwList, noFindList); } + @Override + public abstract TacletIndex copy(); + /** * Inner class to track the occurrences of prefix elements in java blocks */ diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/RuleIndex.java similarity index 98% rename from key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java rename to key.ncore.calculus/src/main/java/org/key_project/prover/indexing/RuleIndex.java index cb2da25f2b..8c127d7eef 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/RuleIndex.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/indexing/RuleIndex.java @@ -1,7 +1,7 @@ /* This file is part of KeY - https://key-project.org * KeY is licensed under the GNU General Public License Version 2 * SPDX-License-Identifier: GPL-2.0-only */ -package de.uka.ilkd.key.proof; +package org.key_project.prover.indexing; import java.util.Set; @@ -57,7 +57,7 @@ public interface RuleIndex extends Cloneable { /** * copies the index */ - TacletIndex copy(); + RuleIndex copy(); /** * clones the index From d9c79e66eced67c11492558aaa9a1c27880887b3 Mon Sep 17 00:00:00 2001 From: Drodt Date: Mon, 14 Jul 2025 08:17:14 +0200 Subject: [PATCH 18/62] Try to distribute responsibilities for features; this commit has errors --- .../main/java/de/uka/ilkd/key/proof/Goal.java | 5 +++ .../ilkd/key/strategy/IntegerStrategy.java | 16 ++++--- .../ilkd/key/strategy/JavaCardDLStrategy.java | 27 ++++++++++++ .../key/strategy/ModularJavaDLStrategy.java | 43 ++++++++++++++++--- .../de/uka/ilkd/key/strategy/Strategy.java | 3 ++ .../rules/integerSimplificationRules.key | 4 +- .../key/proof/rules/ruleSetsDeclarations.key | 1 + .../org/key_project/prover/rules/Rule.java | 8 +++- .../org/key_project/prover/rules/Taclet.java | 1 + 9 files changed, 93 insertions(+), 15 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index 94fa280399..c712f4d9e5 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -637,6 +637,11 @@ public ImmutableList apply(@NonNull final RuleApp ruleApp) { removeLastAppliedRuleApp(); node().setAppliedRuleApp(null); return null; + } catch (IndexOutOfBoundsException e){ + System.out.println(ruleApp.rule().displayName()); + removeLastAppliedRuleApp(); + node().setAppliedRuleApp(null); + return null; } finally { PERF_APP_EXECUTE.getAndAdd(System.nanoTime() - time); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index ceb70ead3d..fbf722806f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -20,6 +20,7 @@ import org.key_project.logic.Term; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; @@ -64,15 +65,15 @@ public IntegerStrategy(Proof proof, StrategyProperties strategyProperties) { // determine configuration nonLinearArithmeticEnabled = StrategyProperties.NON_LIN_ARITH_COMPLETION.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); divAndModuloReasoningEnabled = - nonLinearArithmeticEnabled || StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals( - strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); + nonLinearArithmeticEnabled || StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals( + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY)); stopAtFirstNonCloseableGoal = - strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) - .equals(StrategyProperties.STOPMODE_NONCLOSE); + strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) + .equals(StrategyProperties.STOPMODE_NONCLOSE); // setup cost computations costComputationDispatcher = setupCostComputationF(); @@ -81,6 +82,11 @@ public IntegerStrategy(Proof proof, StrategyProperties strategyProperties) { } + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; + } + private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 222fd10286..67b5afbc23 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -34,6 +34,7 @@ import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.proof.rulefilter.SetRuleFilter; import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; @@ -101,6 +102,11 @@ protected final RuleSetDispatchFeature getInstantiationDispatcher() { return instantiationDispatcher; } + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null || approvalDispatcher.get(rs) != null; + } + protected Feature setupGlobalF(Feature dispatcher) { final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); @@ -785,6 +791,27 @@ private void setupApplyEq(RuleSetDispatchFeature d, IntegerLDT numbers) { MonomialsSmallerThanFeature.create(right, left, numbers)), TermSmallerThanFeature.create(right, left)))))))), longConst(-4000))); + + bindRuleSet(d, "int_apply_equations", + SumFeature.createSum(ifZero(applyTF(FocusProjection.create(0), tf.intF), + add(applyTF(FocusProjection.create(0), tf.monomial), + ScaleFeature.createScaled(FindRightishFeature.create(numbers), 5.0)), + inftyConst()), + ifZero(MatchedAssumesFeature.INSTANCE, + add(CheckApplyEqFeature.INSTANCE, let(equation, AssumptionProjection.create(0), + add(not(applyTF(equation, ff.update)), + // there might be updates in + // front of the assumption + // formula; in this case we wait + // until the updates have + // been applied + let(left, sub(equation, 0), + let(right, sub(equation, 1), ifZero(applyTF(left, tf.intF), + add(applyTF(left, tf.nonNegOrNonCoeffMonomial), + applyTF(right, tf.polynomial), + MonomialsSmallerThanFeature.create(right, left, numbers)), + inftyConst()))))))), + longConst(-4000))); } // ////////////////////////////////////////////////////////////////////////// diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 1c62742761..fda705a171 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; @@ -14,7 +16,9 @@ import org.key_project.prover.rules.RuleApp; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.NumberRuleAppCost; import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.TopRuleAppCost; import org.jspecify.annotations.NonNull; @@ -36,9 +40,8 @@ public ModularJavaDLStrategy(Proof proof, StrategyProperties properties) { @Override protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { - return strategies.stream().map(s -> s.instantiateApp(app, pio, goal, mState)).reduce( - longConst(0).computeCost(app, pio, goal, mState), - RuleAppCost::add); + return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, + RuleAppCost::add, s -> s.instantiateApp(app, pio, goal, mState)); } @Override @@ -49,7 +52,8 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return strategies.stream().allMatch(s -> s.isApprovedApp(app, pio, goal)); + return reduceTillMax(app, true, false, Boolean::logicalAnd, + s -> s.isApprovedApp(app, pio, goal)); } @Override @@ -57,11 +61,36 @@ public Name name() { return NAME; } + private R reduceTillMax(RuleApp app, R init, R max, BiFunction accumulator, + Function mapper) { + for (AbstractFeatureStrategy strategy : strategies) { + var isResponsible = false; + var ruleSets = app.rule().ruleSets(); + if (!ruleSets.hasNext()) isResponsible = true; + else { + while (ruleSets.hasNext()) { + var rs = ruleSets.next(); + if (strategy.isResponsibleFor(rs)) { + isResponsible = true; + break; + } + } + } + if (!isResponsible) { + continue; + } + init = accumulator.apply(init, mapper.apply(strategy)); + if (init == max) { + break; + } + } + return init; + } + @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { - return strategies.stream().map(s -> s.computeCost(app, pos, goal, mState)).reduce( - longConst(0).computeCost(app, pos, goal, mState), - RuleAppCost::add); + return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, + RuleAppCost::add, s -> s.computeCost(app, pos, goal, mState)); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java index 04d24c004b..06abc31c62 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java @@ -10,6 +10,7 @@ import org.key_project.logic.Named; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; @@ -79,4 +80,6 @@ static void updateStrategySettings(Proof proof, StrategyProperties p) { proof.setActiveStrategy(strategy); } + + default boolean isResponsibleFor(RuleSet rs) { return false; } } diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key index ca36ae7762..cea28c7ca0 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key @@ -1785,7 +1785,7 @@ \replacewith(#divideMonomials(applyEqDividend, applyEqDivisor) * (i0 + applyEqDivisor * -1) + applyEqDividend) - \heuristics(polySimp_applyEq, apply_equations, notHumanReadable) + \heuristics(polySimp_applyEq, int_apply_equations, notHumanReadable) }; apply_eq_monomials_rigid { @@ -1794,7 +1794,7 @@ \replacewith(#divideMonomials(applyEqDividend, applyEqDivisorr) * (i0r + applyEqDivisorr * -1) + applyEqDividend) - \heuristics(polySimp_applyEqRigid, apply_equations, notHumanReadable) + \heuristics(polySimp_applyEqRigid, int_apply_equations, notHumanReadable) }; apply_eq_pseudo_eq { diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key index 8141bd44ac..427c6ca142 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key @@ -83,6 +83,7 @@ test_gen_quan_num; order_terms; apply_equations; + int_apply_equations; insert_eq_nonrigid; simplify_literals; eval_literals; diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Rule.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Rule.java index 8f0bd03be2..c0ca67ba9b 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Rule.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Rule.java @@ -3,6 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-only */ package org.key_project.prover.rules; +import java.util.Collections; +import java.util.Iterator; + import org.key_project.logic.Named; import org.key_project.prover.proof.ProofGoal; @@ -12,6 +15,10 @@ /// It provides access to the rule application logic. public interface Rule extends Named { + default Iterator ruleSets() { + return Collections.emptyIterator(); + } + /// Returns the rule executor for this rule. /// The rule executor encapsulates the logic for rule applications. /// @@ -25,5 +32,4 @@ public interface Rule extends Named { default @NonNull String displayName() { return name().toString(); } - } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Taclet.java b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Taclet.java index fa599589f7..9a8c547a06 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Taclet.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/rules/Taclet.java @@ -297,6 +297,7 @@ public ChoiceExpr getChoices() { } /// @return an iterator over the rule sets. + @Override public Iterator ruleSets() { return ruleSets.iterator(); } From bd01ba24cfdf086d44863d7ed31eaa9a0da5cd5d Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Thu, 17 Jul 2025 09:58:51 +0200 Subject: [PATCH 19/62] Added javadoc --- .../de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java index 388e47a96d..2debcadbb1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java @@ -134,6 +134,11 @@ public void instantiateApp(RuleApp app, PosInOccurrence pio, } while (btManager.backtrack()); } + /** + * returns the service instance for access to {@link de.uka.ilkd.key.ldt.LDT}s + * + * @return the services for access to the meta logic + */ protected final Services getServices() { return getProof().getServices(); } From bf7249abcecff5c8a52339b34a82f53447ce6610 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 17 Jul 2025 12:22:49 +0200 Subject: [PATCH 20/62] Intermediate commit: Move common features to modular strat; fix: instApp method for instApp --- .../main/java/de/uka/ilkd/key/proof/Goal.java | 2 +- .../ilkd/key/strategy/IntegerStrategy.java | 22 ++++---- .../ilkd/key/strategy/JavaCardDLStrategy.java | 11 ++-- .../key/strategy/ModularJavaDLStrategy.java | 52 ++++++++++++++++--- .../key/strategy/StaticFeatureCollection.java | 8 +++ .../key/strategy/feature/PrintFeature.java | 3 ++ 6 files changed, 76 insertions(+), 22 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index c712f4d9e5..7ff80ef9a9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -637,7 +637,7 @@ public ImmutableList apply(@NonNull final RuleApp ruleApp) { removeLastAppliedRuleApp(); node().setAppliedRuleApp(null); return null; - } catch (IndexOutOfBoundsException e){ + } catch (IndexOutOfBoundsException e) { System.out.println(ruleApp.rule().displayName()); removeLastAppliedRuleApp(); node().setAppliedRuleApp(null); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index fbf722806f..b27b9ae681 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -643,13 +643,17 @@ private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature notAllow // the rule application in isApprovedApp). This is not // perfect, because it is not possible to distinguish between the // re-cost-computation delay and the normal costs for a rule application - bindRuleSet(d, "inEqSimp_nonLin_multiply", add(applyTF("multLeft", tf.nonNegMonomial), - applyTF("multRight", tf.polynomial), - ifZero(MatchedAssumesFeature.INSTANCE, - SumFeature.createSum(applyTF("multFacLeft", tf.nonNegMonomial), - ifZero(applyTF("multRight", tf.literal), longConst(-100)), - ifZero(applyTF("multFacRight", tf.literal), longConst(-100), - applyTF("multFacRight", tf.polynomial)), + bindRuleSet(d, "inEqSimp_nonLin_multiply", print("nonLin_mult", add( + applyTF("multLeft", tf.nonNegMonomial), + print("multRight", applyTF("multRight", tf.polynomial)), + ifZero(print("assumes", MatchedAssumesFeature.INSTANCE), + SumFeature.createSum( + print("multFacLeft", applyTF("multFacLeft", tf.nonNegMonomial)), + print("mult.multRight-ifZero", + ifZero(applyTF("multRight", tf.literal), longConst(-100))), + print("mult.multFacRight-ifZero", + ifZero(applyTF("multFacRight", tf.literal), longConst(-100), + applyTF("multFacRight", tf.polynomial))), /* * ifZero ( applyTF ( "multRight", tf.literal ), longConst ( -100 ), applyTF ( * "multRight", tf.polynomial ) ), ifZero ( applyTF ( "multFacRight", tf.literal @@ -668,7 +672,7 @@ private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature notAllow * rec ( tf.addF, longTermConst ( 4 ) ) ), applyTF ( "multFacRight", rec ( tf.addF, * longTermConst ( 4 ) ) ), */ - ), notAllowedF))); + ), notAllowedF)))); } private void setupInEqSimpInstantiation(RuleSetDispatchFeature d) { @@ -779,7 +783,7 @@ private void setupInEqCaseDistinctions(RuleSetDispatchFeature d) { // longTermConst ( 5 ) ) ) )))); - bindRuleSet(d, "inEqSimp_signCases", posNegSplitting); + bindRuleSet(d, "inEqSimp_signCases", print("signCases", posNegSplitting)); final Feature strengthening = forEach(intRel, SequentFormulasGenerator.antecedent(), SumFeature.createSum( diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 67b5afbc23..de82b63ff8 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -104,11 +104,11 @@ protected final RuleSetDispatchFeature getInstantiationDispatcher() { @Override public boolean isResponsibleFor(RuleSet rs) { - return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null || approvalDispatcher.get(rs) != null; + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null + || approvalDispatcher.get(rs) != null; } protected Feature setupGlobalF(Feature dispatcher) { - final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); final Feature methodSpecF; final String methProp = @@ -203,14 +203,13 @@ protected Feature setupGlobalF(Feature dispatcher) { // final Feature smtF = smtFeature(inftyConst()); - return SumFeature.createSum(AutomatedRuleFeature.getInstance(), - NonDuplicateAppFeature.INSTANCE, + return SumFeature.createSum( // splitF, // strengthenConstraints, - AgeFeature.INSTANCE, oneStepSimplificationF, mergeRuleF, + oneStepSimplificationF, mergeRuleF, // smtF, methodSpecF, queryF, depSpecF, loopInvF, blockFeature, loopBlockFeature, - loopBlockApplyHeadFeature, ifMatchedF, dispatcher); + loopBlockApplyHeadFeature, dispatcher); } private Feature oneStepSimplificationFeature(Feature cost) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index fda705a171..541854fc93 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -10,6 +10,9 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.feature.AgeFeature; +import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; +import de.uka.ilkd.key.strategy.feature.NonDuplicateAppFeature; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -19,6 +22,8 @@ import org.key_project.prover.strategy.costbased.NumberRuleAppCost; import org.key_project.prover.strategy.costbased.RuleAppCost; import org.key_project.prover.strategy.costbased.TopRuleAppCost; +import org.key_project.prover.strategy.costbased.feature.AutomatedRuleFeature; +import org.key_project.prover.strategy.costbased.feature.Feature; import org.jspecify.annotations.NonNull; @@ -28,20 +33,29 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final List strategies = new ArrayList<>(); private final StrategyProperties strategyProperties; + private final Feature reduceCostTillMaxF; + private final Feature reduceInstTillMaxF; public ModularJavaDLStrategy(Proof proof, StrategyProperties properties) { super(proof); strategies.add(new IntegerStrategy(proof, properties)); strategies.add(new StringStrategy(proof, properties)); strategies.add(new JavaCardDLStrategy(proof, properties)); + reduceCostTillMaxF = new ReduceCostTillMaxFeature(); + reduceInstTillMaxF = new ReduceInstTillMaxFeature(); this.strategyProperties = (StrategyProperties) properties.clone(); } @Override protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { - return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, - RuleAppCost::add, s -> s.instantiateApp(app, pio, goal, mState)); + // TODO: enable + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + Feature totalCost = + add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, + reduceInstTillMaxF, + AgeFeature.INSTANCE, ifMatchedF); + return totalCost.computeCost(app, pio, goal, mState); } @Override @@ -52,7 +66,10 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return reduceTillMax(app, true, false, Boolean::logicalAnd, + boolean isApproved = + NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, + new MutableState()) != TopRuleAppCost.INSTANCE; + return reduceTillMax(app, isApproved, false, Boolean::logicalAnd, s -> s.isApprovedApp(app, pio, goal)); } @@ -66,7 +83,8 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu for (AbstractFeatureStrategy strategy : strategies) { var isResponsible = false; var ruleSets = app.rule().ruleSets(); - if (!ruleSets.hasNext()) isResponsible = true; + if (!ruleSets.hasNext()) + isResponsible = true; else { while (ruleSets.hasNext()) { var rs = ruleSets.next(); @@ -90,7 +108,29 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { - return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, - RuleAppCost::add, s -> s.computeCost(app, pos, goal, mState)); + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + Feature totalCost = + add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, + reduceCostTillMaxF, + AgeFeature.INSTANCE, ifMatchedF); + return totalCost.computeCost(app, pos, goal, mState); + } + + private class ReduceCostTillMaxFeature implements Feature { + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { + return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, + RuleAppCost::add, s -> s.computeCost(app, pos, goal, mState)); + } + } + + private class ReduceInstTillMaxFeature implements Feature { + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { + return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, + RuleAppCost::add, s -> s.instantiateApp(app, pos, (Goal) goal, mState)); + } } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StaticFeatureCollection.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StaticFeatureCollection.java index 1afbc52f4a..bb9198ffa6 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StaticFeatureCollection.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StaticFeatureCollection.java @@ -520,4 +520,12 @@ protected static TermFeature constantTermFeature() { return TermPredicateTermFeature .create(term -> term.op() instanceof Function && term.arity() == 0); } + + protected static Feature print(Feature f) { + return new PrintFeature(f); + } + + protected static Feature print(String msg, Feature f) { + return new PrintFeature(msg, f); + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/PrintFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/PrintFeature.java index 936b503ba1..72480202f9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/PrintFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/PrintFeature.java @@ -38,6 +38,9 @@ public PrintFeature(Feature f) { PosInOccurrence pos, Goal goal, MutableState mState) { RuleAppCost cost = f.computeCost(app, pos, goal, mState); + System.out.println( + prefix + ":" + cost.toString() + ":" + (pos != null ? pos.subTerm() + ":" : "") + ":" + + app.rule().name()); LOGGER.debug("{}:{}:{}{}", prefix, cost.toString(), pos != null ? pos.subTerm() + ":" : "", app.rule().name()); return cost; From 4be0bf7b53e36562e3290c7498af8b3efdd6b054 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 17 Jul 2025 13:36:04 +0200 Subject: [PATCH 21/62] Clean up --- .../key/strategy/AbstractFeatureStrategy.java | 21 ++++++++------ .../ilkd/key/strategy/IntegerStrategy.java | 20 ++++++------- .../key/strategy/ModularJavaDLStrategy.java | 29 ++++++++++--------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java index 2debcadbb1..612cf51c92 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java @@ -166,22 +166,25 @@ protected Feature oneOf(Feature feature0, Feature feature1) { return oneOf(new Feature[] { feature0, feature1 }); } - // it is possible to turn off the method instantiate, - // which can be useful in order to use the same feature definitions both for - // cost computation and instantiation - - private boolean instantiateActive = false; + /// It is possible to turn off the method instantiate, + /// which can be useful in order to use the same feature definitions both for + /// cost computation and instantiation. + /// + /// Counts nesting depth of instantiation activation to avoid premature deactivation. + private short instantiateActive = 0; protected void enableInstantiate() { - instantiateActive = true; + instantiateActive++; + assert instantiateActive >= 0 : "overflow occurred"; } protected void disableInstantiate() { - instantiateActive = false; + instantiateActive--; + assert instantiateActive >= 0; } protected Feature instantiate(Name sv, ProjectionToTerm value) { - if (instantiateActive) { + if (instantiateActive != 0) { return SVInstantiationCP.create(sv, value); } else { return longConst(0); @@ -189,7 +192,7 @@ protected Feature instantiate(Name sv, ProjectionToTerm value) { } protected Feature instantiateTriggeredVariable(ProjectionToTerm value) { - if (instantiateActive) { + if (instantiateActive != 0) { return SVInstantiationCP.createTriggeredVarCP(value); } else { return longConst(0); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index b27b9ae681..3d1f5e2706 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -643,17 +643,15 @@ private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature notAllow // the rule application in isApprovedApp). This is not // perfect, because it is not possible to distinguish between the // re-cost-computation delay and the normal costs for a rule application - bindRuleSet(d, "inEqSimp_nonLin_multiply", print("nonLin_mult", add( + bindRuleSet(d, "inEqSimp_nonLin_multiply", add( applyTF("multLeft", tf.nonNegMonomial), - print("multRight", applyTF("multRight", tf.polynomial)), - ifZero(print("assumes", MatchedAssumesFeature.INSTANCE), + applyTF("multRight", tf.polynomial), + ifZero(MatchedAssumesFeature.INSTANCE, SumFeature.createSum( - print("multFacLeft", applyTF("multFacLeft", tf.nonNegMonomial)), - print("mult.multRight-ifZero", - ifZero(applyTF("multRight", tf.literal), longConst(-100))), - print("mult.multFacRight-ifZero", - ifZero(applyTF("multFacRight", tf.literal), longConst(-100), - applyTF("multFacRight", tf.polynomial))), + applyTF("multFacLeft", tf.nonNegMonomial), + ifZero(applyTF("multRight", tf.literal), longConst(-100)), + ifZero(applyTF("multFacRight", tf.literal), longConst(-100), + applyTF("multFacRight", tf.polynomial)), /* * ifZero ( applyTF ( "multRight", tf.literal ), longConst ( -100 ), applyTF ( * "multRight", tf.polynomial ) ), ifZero ( applyTF ( "multFacRight", tf.literal @@ -672,7 +670,7 @@ private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature notAllow * rec ( tf.addF, longTermConst ( 4 ) ) ), applyTF ( "multFacRight", rec ( tf.addF, * longTermConst ( 4 ) ) ), */ - ), notAllowedF)))); + ), notAllowedF))); } private void setupInEqSimpInstantiation(RuleSetDispatchFeature d) { @@ -783,7 +781,7 @@ private void setupInEqCaseDistinctions(RuleSetDispatchFeature d) { // longTermConst ( 5 ) ) ) )))); - bindRuleSet(d, "inEqSimp_signCases", print("signCases", posNegSplitting)); + bindRuleSet(d, "inEqSimp_signCases", posNegSplitting); final Feature strengthening = forEach(intRel, SequentFormulasGenerator.antecedent(), SumFeature.createSum( diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 541854fc93..4a7bb7b9a1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -28,7 +28,6 @@ import org.jspecify.annotations.NonNull; public class ModularJavaDLStrategy extends AbstractFeatureStrategy { - public static final Name NAME = new Name("Modular JavaDL Strategy"); private final List strategies = new ArrayList<>(); @@ -41,20 +40,21 @@ public ModularJavaDLStrategy(Proof proof, StrategyProperties properties) { strategies.add(new IntegerStrategy(proof, properties)); strategies.add(new StringStrategy(proof, properties)); strategies.add(new JavaCardDLStrategy(proof, properties)); - reduceCostTillMaxF = new ReduceCostTillMaxFeature(); - reduceInstTillMaxF = new ReduceInstTillMaxFeature(); + reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost); + reduceInstTillMaxF = new ReduceTillMaxFeature(AbstractFeatureStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); } @Override protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { - // TODO: enable + enableInstantiate(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); Feature totalCost = add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, reduceInstTillMaxF, AgeFeature.INSTANCE, ifMatchedF); + disableInstantiate(); return totalCost.computeCost(app, pio, goal, mState); } @@ -116,21 +116,24 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu return totalCost.computeCost(app, pos, goal, mState); } - private class ReduceCostTillMaxFeature implements Feature { - @Override - public > RuleAppCost computeCost(RuleApp app, - PosInOccurrence pos, GOAL goal, MutableState mState) { - return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, - RuleAppCost::add, s -> s.computeCost(app, pos, goal, mState)); - } + @FunctionalInterface + private interface StrategyCostFunction { + RuleAppCost compute(AbstractFeatureStrategy strategy, RuleApp app, + PosInOccurrence pos, Goal goal, MutableState mState); } - private class ReduceInstTillMaxFeature implements Feature { + private class ReduceTillMaxFeature implements Feature { + private final StrategyCostFunction mapper; + + ReduceTillMaxFeature(StrategyCostFunction mapper) { + this.mapper = mapper; + } + @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, - RuleAppCost::add, s -> s.instantiateApp(app, pos, (Goal) goal, mState)); + RuleAppCost::add, s -> mapper.compute(s, app, pos, (Goal) goal, mState)); } } } From 231bc41a63cadb7eec673671e59d542c33b2540c Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 17 Jul 2025 14:23:44 +0200 Subject: [PATCH 22/62] Modular UI Strategy panel --- .../uka/ilkd/key/proof/init/JavaProfile.java | 4 +- .../key/strategy/IntegerStrategyFactory.java | 61 +++++++ .../strategy/JavaCardDLStrategyFactory.java | 98 +---------- .../key/strategy/ModularJavaDLStrategy.java | 7 +- .../ModularJavaDLStrategyFactory.java | 156 ++++++++++++++++++ .../key/strategy/StringStrategyFactory.java | 26 +++ .../AbstractStrategyPropertyDefinition.java | 4 +- 7 files changed, 255 insertions(+), 101 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/init/JavaProfile.java b/key.core/src/main/java/de/uka/ilkd/key/proof/init/JavaProfile.java index d91cbbd771..3853814832 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/init/JavaProfile.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/init/JavaProfile.java @@ -19,7 +19,7 @@ import de.uka.ilkd.key.rule.label.TermLabelRefactoring; import de.uka.ilkd.key.rule.merge.MergeRule; import de.uka.ilkd.key.smt.newsmt2.DefinedSymbolsHandler; -import de.uka.ilkd.key.strategy.JavaCardDLStrategyFactory; +import de.uka.ilkd.key.strategy.ModularJavaDLStrategyFactory; import de.uka.ilkd.key.strategy.StrategyFactory; import org.key_project.prover.rules.RuleApp; @@ -48,7 +48,7 @@ public class JavaProfile extends AbstractProfile { public static JavaProfile defaultInstance; public static JavaProfile defaultInstancePermissions; - public static final StrategyFactory DEFAULT = new JavaCardDLStrategyFactory(); + public static final StrategyFactory DEFAULT = new ModularJavaDLStrategyFactory(); private boolean permissions = false; diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java new file mode 100644 index 0000000000..e9645d5422 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java @@ -0,0 +1,61 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.OneOfStrategyPropertyDefinition; +import de.uka.ilkd.key.strategy.definition.StrategyPropertyValueDefinition; +import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; + +import org.key_project.logic.Name; + +public class IntegerStrategyFactory implements StrategyFactory { + public static final String TOOL_TIP_ARITHMETIC_BASE = "" + "Basic arithmetic support:" + + "
    " + "
  • Simplification of polynomial expressions
  • " + + "
  • Computation of Gröbner Bases for polynomials in the antecedent
  • " + + "
  • (Partial) Omega procedure for handling linear inequations
  • " + "
" + + ""; + public static final String TOOL_TIP_ARITHMETIC_DEF_OPS = + "" + "Automatically expand defined symbols like:" + "
    " + + "
  • /, %, jdiv, jmod, ...
  • " + + "
  • int_RANGE, short_MIN, ...
  • " + + "
  • inInt, inByte, ...
  • " + + "
  • addJint, mulJshort, ...
  • " + "
" + ""; + public static final String TOOL_TIP_ARITHMETIC_MODEL_SEARCH = "" + + "Support for non-linear inequations and model search.
" + "In addition, this performs:" + + "
    " + "
  • Multiplication of inequations with each other
  • " + + "
  • Systematic case distinctions (cuts)
  • " + "
" + + "This method is guaranteed to find counterexamples for
" + + "invalid goals that only contain polynomial (in)equations.
" + + "Such counterexamples turn up as trivially unprovable goals.
" + + "It is also able to prove many more valid goals involving
" + + "(in)equations, but will in general not terminate on such goals." + ""; + + private static OneOfStrategyPropertyDefinition getArithmeticTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY, + "Arithmetic treatment", + new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_NONE, "Basic", + TOOL_TIP_ARITHMETIC_BASE), + new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_DEF_OPS, "DefOps", + TOOL_TIP_ARITHMETIC_DEF_OPS), + new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_COMPLETION, + "Model Search", TOOL_TIP_ARITHMETIC_MODEL_SEARCH)); + } + + @Override + public IntegerStrategy create(Proof proof, StrategyProperties strategyProperties) { + return new IntegerStrategy(proof, strategyProperties); + } + + @Override + public StrategySettingsDefinition getSettingsDefinition() { + final OneOfStrategyPropertyDefinition arithmeticTreatment = getArithmeticTreatment(); + return new StrategySettingsDefinition("Integer Options", arithmeticTreatment); + } + + @Override + public Name name() { + return IntegerStrategy.NAME; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index 1eac88125f..050b45754e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java @@ -29,13 +29,6 @@ public class JavaCardDLStrategyFactory implements StrategyFactory { */ public static final Name NAME = new Name(JavaCardDLStrategy.JAVA_CARD_DL_STRATEGY); - public static final String TOOL_TIP_STOP_AT_DEFAULT = - "Stop when (i) the maximum number of rule
" - + "applications is reached or (ii) no more rules are
" - + "applicable on the proof tree."; - public static final String TOOL_TIP_STOP_AT_UNCLOSABLE = - "Stop as soon as the first not automatically
" - + "closable goal is encountered."; public static final String TOOL_TIP_OSS_ON = "" + "Turns on One Step Simplification. This will result in
" + "(sometimes significantly) shorter proofs which,
" @@ -189,26 +182,6 @@ public class JavaCardDLStrategyFactory implements StrategyFactory { public static final String TOOL_TIP_EXPAND_LOCAL_QUERIES_OFF = "" + "Expansion of local queries is turned off.
" + "This setting is independent of the query treatment setting." + ""; - public static final String TOOL_TIP_ARITHMETIC_BASE = "" + "Basic arithmetic support:" - + "
    " + "
  • Simplification of polynomial expressions
  • " - + "
  • Computation of Gröbner Bases for polynomials in the antecedent
  • " - + "
  • (Partial) Omega procedure for handling linear inequations
  • " + "
" - + ""; - public static final String TOOL_TIP_ARITHMETIC_DEF_OPS = - "" + "Automatically expand defined symbols like:" + "
    " - + "
  • /, %, jdiv, jmod, ...
  • " - + "
  • int_RANGE, short_MIN, ...
  • " - + "
  • inInt, inByte, ...
  • " - + "
  • addJint, mulJshort, ...
  • " + "
" + ""; - public static final String TOOL_TIP_ARITHMETIC_MODEL_SEARCH = "" - + "Support for non-linear inequations and model search.
" + "In addition, this performs:" - + "
    " + "
  • Multiplication of inequations with each other
  • " - + "
  • Systematic case distinctions (cuts)
  • " + "
" - + "This method is guaranteed to find counterexamples for
" - + "invalid goals that only contain polynomial (in)equations.
" - + "Such counterexamples turn up as trivially unprovable goals.
" - + "It is also able to prove many more valid goals involving
" - + "(in)equations, but will in general not terminate on such goals." + ""; public static final String TOOL_TIP_QUANTIFIER_NONE = "" + "Do not instantiate quantified formulas automatically" + ""; public static final String TOOL_TIP_QUANTIFIER_NO_SPLITS = "" @@ -257,29 +230,6 @@ public class JavaCardDLStrategyFactory implements StrategyFactory { public JavaCardDLStrategyFactory() { } - public static final String toolTipUserOff(int i) { - return "Taclets of the rule set \"userTaclets" + i + "\" are not applied automatically"; - } - - public static final String toolTipUserLow(int i) { - return "Taclets of the rule set \"userTaclets" + i - + "\" are applied automatically with low priority"; - } - - public static final String toolTipUserHigh(int i) { - return "Taclets of the rule set \"userTaclets" + i - + "\" are applied automatically with high priority"; - } - - private static OneOfStrategyPropertyDefinition getStopAt() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.STOPMODE_OPTIONS_KEY, - "Stop at", - new StrategyPropertyValueDefinition(StrategyProperties.STOPMODE_DEFAULT, "Default", - TOOL_TIP_STOP_AT_DEFAULT), - new StrategyPropertyValueDefinition(StrategyProperties.STOPMODE_NONCLOSE, "Unclosable", - TOOL_TIP_STOP_AT_UNCLOSABLE)); - } - private static OneOfStrategyPropertyDefinition getOssUsage() { return new OneOfStrategyPropertyDefinition(StrategyProperties.OSS_OPTIONS_KEY, "One Step Simplification", @@ -382,17 +332,6 @@ private static OneOfStrategyPropertyDefinition getQueryTreatment() { TOOL_TIP_QUERY_OFF)); } - private static OneOfStrategyPropertyDefinition getArithmeticTreatment() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY, - "Arithmetic treatment", - new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_NONE, "Basic", - TOOL_TIP_ARITHMETIC_BASE), - new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_DEF_OPS, "DefOps", - TOOL_TIP_ARITHMETIC_DEF_OPS), - new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_COMPLETION, - "Model Search", TOOL_TIP_ARITHMETIC_MODEL_SEARCH)); - } - private static OneOfStrategyPropertyDefinition getQuantifierTreatment() { return new OneOfStrategyPropertyDefinition(StrategyProperties.QUANTIFIERS_OPTIONS_KEY, "Quantifier treatment", 2, @@ -429,33 +368,9 @@ private static OneOfStrategyPropertyDefinition getAutoInduction() { TOOL_TIP_AUTO_INDUCTION_OFF)); } - private static OneOfStrategyPropertyDefinition getUserOptions() { - // User properties - List props = new LinkedList<>(); - for (int i = 1; i <= StrategyProperties.USER_TACLETS_NUM; ++i) { - OneOfStrategyPropertyDefinition user = new OneOfStrategyPropertyDefinition( - StrategyProperties.userTacletsOptionsKey(i), i + ": ", - new StrategyPropertyValueDefinition(StrategyProperties.USER_TACLETS_OFF, "Off", - toolTipUserOff(i), 3, 1), - new StrategyPropertyValueDefinition(StrategyProperties.USER_TACLETS_LOW, - "Low prior.", toolTipUserLow(i), 4, 2), - new StrategyPropertyValueDefinition(StrategyProperties.USER_TACLETS_HIGH, - "High prior.", toolTipUserHigh(i), 6, 2)); - props.add(user); - } - - return new OneOfStrategyPropertyDefinition(null, "User-specific taclet sets", - "" + "These options define whether user- and problem-specific taclet sets
" - + "are applied automatically by the strategy. Problem-specific taclets
" - + "can be defined in the \\rules-section of a .key-problem file. For
" - + "automatic application, the taclets have to contain a clause
" - + "\\heuristics(userTaclets1), \\heuristics(userTaclets2), etc." + "", - -1, props.toArray(new AbstractStrategyPropertyDefinition[0])); - } - @Override - public Strategy<@NonNull Goal> create(Proof proof, StrategyProperties strategyProperties) { - return new ModularJavaDLStrategy(proof, strategyProperties); + public JavaCardDLStrategy create(Proof proof, StrategyProperties strategyProperties) { + return new JavaCardDLStrategy(proof, strategyProperties); } @Override @@ -466,7 +381,6 @@ public Name name() { @Override public StrategySettingsDefinition getSettingsDefinition() { // Properties - final OneOfStrategyPropertyDefinition stopAt = getStopAt(); final OneOfStrategyPropertyDefinition ossUsage = getOssUsage(); final OneOfStrategyPropertyDefinition proofSplitting = getProofSplitting(); final OneOfStrategyPropertyDefinition loopTreatment = getLoopTreatment(); @@ -476,15 +390,13 @@ public StrategySettingsDefinition getSettingsDefinition() { getMergePointStatementTreatment(); final OneOfStrategyPropertyDefinition dependencyContracts = getDependencyContracts(); final OneOfStrategyPropertyDefinition queryTreatment = getQueryTreatment(); - final OneOfStrategyPropertyDefinition arithmeticTreatment = getArithmeticTreatment(); final OneOfStrategyPropertyDefinition quantifierTreatment = getQuantifierTreatment(); final OneOfStrategyPropertyDefinition classAxiom = getClassAxiom(); final OneOfStrategyPropertyDefinition autoInduction = getAutoInduction(); - final OneOfStrategyPropertyDefinition userOptions = getUserOptions(); // Model - return new StrategySettingsDefinition("Java DL Options", stopAt, ossUsage, proofSplitting, + return new StrategySettingsDefinition("Java DL Options", ossUsage, proofSplitting, loopTreatment, blockTreatment, methodTreatment, mergePointStatementTreatment, - dependencyContracts, queryTreatment, arithmeticTreatment, quantifierTreatment, - classAxiom, autoInduction, userOptions); + dependencyContracts, queryTreatment, quantifierTreatment, + classAxiom, autoInduction); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 4a7bb7b9a1..4b9df1d0c5 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -35,11 +35,10 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final Feature reduceCostTillMaxF; private final Feature reduceInstTillMaxF; - public ModularJavaDLStrategy(Proof proof, StrategyProperties properties) { + public ModularJavaDLStrategy(Proof proof, List componentStrategies, + StrategyProperties properties) { super(proof); - strategies.add(new IntegerStrategy(proof, properties)); - strategies.add(new StringStrategy(proof, properties)); - strategies.add(new JavaCardDLStrategy(proof, properties)); + strategies.addAll(componentStrategies); reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost); reduceInstTillMaxF = new ReduceTillMaxFeature(AbstractFeatureStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java new file mode 100644 index 0000000000..401b0ba8b6 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -0,0 +1,156 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.AbstractStrategyPropertyDefinition; +import de.uka.ilkd.key.strategy.definition.OneOfStrategyPropertyDefinition; +import de.uka.ilkd.key.strategy.definition.StrategyPropertyValueDefinition; +import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; + +import org.key_project.logic.Name; + +import org.jspecify.annotations.NonNull; + +/** + * + * @author Kai Wallisch + */ +public class ModularJavaDLStrategyFactory implements StrategyFactory { + private final List componentFactories = Arrays.asList( + new IntegerStrategyFactory(), new StringStrategyFactory(), new JavaCardDLStrategyFactory()); + + /** + * The unique {@link Name} of this {@link StrategyFactory}. + */ + public static final Name NAME = ModularJavaDLStrategy.NAME; + + public static final String TOOL_TIP_STOP_AT_DEFAULT = + "Stop when (i) the maximum number of rule
" + + "applications is reached or (ii) no more rules are
" + + "applicable on the proof tree."; + public static final String TOOL_TIP_STOP_AT_UNCLOSABLE = + "Stop as soon as the first not automatically
" + + "closable goal is encountered."; + public static final String TOOL_TIP_ARITHMETIC_BASE = "" + "Basic arithmetic support:" + + "
    " + "
  • Simplification of polynomial expressions
  • " + + "
  • Computation of Gröbner Bases for polynomials in the antecedent
  • " + + "
  • (Partial) Omega procedure for handling linear inequations
  • " + "
" + + ""; + public static final String TOOL_TIP_ARITHMETIC_DEF_OPS = + "" + "Automatically expand defined symbols like:" + "
    " + + "
  • /, %, jdiv, jmod, ...
  • " + + "
  • int_RANGE, short_MIN, ...
  • " + + "
  • inInt, inByte, ...
  • " + + "
  • addJint, mulJshort, ...
  • " + "
" + ""; + public static final String TOOL_TIP_ARITHMETIC_MODEL_SEARCH = "" + + "Support for non-linear inequations and model search.
" + "In addition, this performs:" + + "
    " + "
  • Multiplication of inequations with each other
  • " + + "
  • Systematic case distinctions (cuts)
  • " + "
" + + "This method is guaranteed to find counterexamples for
" + + "invalid goals that only contain polynomial (in)equations.
" + + "Such counterexamples turn up as trivially unprovable goals.
" + + "It is also able to prove many more valid goals involving
" + + "(in)equations, but will in general not terminate on such goals." + ""; + + public ModularJavaDLStrategyFactory() { + } + + public static final String toolTipUserOff(int i) { + return "Taclets of the rule set \"userTaclets" + i + "\" are not applied automatically"; + } + + public static final String toolTipUserLow(int i) { + return "Taclets of the rule set \"userTaclets" + i + + "\" are applied automatically with low priority"; + } + + public static final String toolTipUserHigh(int i) { + return "Taclets of the rule set \"userTaclets" + i + + "\" are applied automatically with high priority"; + } + + private static OneOfStrategyPropertyDefinition getStopAt() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.STOPMODE_OPTIONS_KEY, + "Stop at", + new StrategyPropertyValueDefinition(StrategyProperties.STOPMODE_DEFAULT, "Default", + TOOL_TIP_STOP_AT_DEFAULT), + new StrategyPropertyValueDefinition(StrategyProperties.STOPMODE_NONCLOSE, "Unclosable", + TOOL_TIP_STOP_AT_UNCLOSABLE)); + } + + private static OneOfStrategyPropertyDefinition getArithmeticTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY, + "Arithmetic treatment", + new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_NONE, "Basic", + TOOL_TIP_ARITHMETIC_BASE), + new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_DEF_OPS, "DefOps", + TOOL_TIP_ARITHMETIC_DEF_OPS), + new StrategyPropertyValueDefinition(StrategyProperties.NON_LIN_ARITH_COMPLETION, + "Model Search", TOOL_TIP_ARITHMETIC_MODEL_SEARCH)); + } + + private static OneOfStrategyPropertyDefinition getUserOptions() { + // User properties + List props = new LinkedList<>(); + for (int i = 1; i <= StrategyProperties.USER_TACLETS_NUM; ++i) { + OneOfStrategyPropertyDefinition user = new OneOfStrategyPropertyDefinition( + StrategyProperties.userTacletsOptionsKey(i), i + ": ", + new StrategyPropertyValueDefinition(StrategyProperties.USER_TACLETS_OFF, "Off", + toolTipUserOff(i), 3, 1), + new StrategyPropertyValueDefinition(StrategyProperties.USER_TACLETS_LOW, + "Low prior.", toolTipUserLow(i), 4, 2), + new StrategyPropertyValueDefinition(StrategyProperties.USER_TACLETS_HIGH, + "High prior.", toolTipUserHigh(i), 6, 2)); + props.add(user); + } + + return new OneOfStrategyPropertyDefinition(null, "User-specific taclet sets", + "" + "These options define whether user- and problem-specific taclet sets
" + + "are applied automatically by the strategy. Problem-specific taclets
" + + "can be defined in the \\rules-section of a .key-problem file. For
" + + "automatic application, the taclets have to contain a clause
" + + "\\heuristics(userTaclets1), \\heuristics(userTaclets2), etc." + "", + -1, props.toArray(new AbstractStrategyPropertyDefinition[0])); + } + + @Override + public Strategy<@NonNull Goal> create(Proof proof, StrategyProperties strategyProperties) { + List componentStrategies = componentFactories.stream() + .map(f -> (AbstractFeatureStrategy) f.create(proof, strategyProperties)) + .collect(Collectors.toList()); + return new ModularJavaDLStrategy(proof, componentStrategies, strategyProperties); + } + + @Override + public Name name() { + return NAME; + } + + @Override + public StrategySettingsDefinition getSettingsDefinition() { + // Properties + final OneOfStrategyPropertyDefinition stopAt = getStopAt(); + final OneOfStrategyPropertyDefinition userOptions = getUserOptions(); + + List componentSettings = componentFactories.stream() + .flatMap(f -> f.getSettingsDefinition().getProperties().stream()) + .collect(Collectors.toCollection(ArrayList::new)); + componentSettings.addFirst(stopAt); + componentSettings.add(userOptions); + + AbstractStrategyPropertyDefinition[] properties = + componentSettings.toArray(new AbstractStrategyPropertyDefinition[0]); + + // Model + return new StrategySettingsDefinition("Global Options", properties); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java new file mode 100644 index 0000000000..0756a89643 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java @@ -0,0 +1,26 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; + +import org.key_project.logic.Name; + +public class StringStrategyFactory implements StrategyFactory { + @Override + public StringStrategy create(Proof proof, StrategyProperties strategyProperties) { + return new StringStrategy(proof, strategyProperties); + } + + @Override + public StrategySettingsDefinition getSettingsDefinition() { + return new StrategySettingsDefinition("String Options"); + } + + @Override + public Name name() { + return StringStrategy.NAME; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/definition/AbstractStrategyPropertyDefinition.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/definition/AbstractStrategyPropertyDefinition.java index 080b987c5e..f96a252ecc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/definition/AbstractStrategyPropertyDefinition.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/definition/AbstractStrategyPropertyDefinition.java @@ -62,9 +62,9 @@ public String getApiKey() { } /** - * Returns the human readable name of the property. + * Returns the human-readable name of the property. * - * @return The human readable name of the property. + * @return The human-readable name of the property. */ public String getName() { return name; From 42c9d2acd6321d466f1d67875c0ff6f1a3a06daf Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Thu, 17 Jul 2025 15:57:18 +0200 Subject: [PATCH 23/62] Add responsibilities to StringStrategy --- .../java/de/uka/ilkd/key/strategy/StringStrategy.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index 2d2297efc0..42b2069108 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -15,6 +15,7 @@ import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; @@ -51,6 +52,11 @@ public StringStrategy(Proof proof, StrategyProperties strategyProperties) { .equals(StrategyProperties.STOPMODE_NONCLOSE); } + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null; + } + private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); setUpStringNormalisation(d); @@ -149,12 +155,10 @@ public boolean isStopAtFirstNonCloseableGoal() { return stopAtFirstNonCloseableGoal; } - @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { return !(NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, new MutableState()) == TopRuleAppCost.INSTANCE); - } @Override From 434e58f02f205f33b2a8a1776887aa7a0cf1be7b Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 23 Jul 2025 10:03:36 +0200 Subject: [PATCH 24/62] Rename UI text --- .../de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java index 401b0ba8b6..ed92d79688 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -151,6 +151,6 @@ public StrategySettingsDefinition getSettingsDefinition() { componentSettings.toArray(new AbstractStrategyPropertyDefinition[0]); // Model - return new StrategySettingsDefinition("Global Options", properties); + return new StrategySettingsDefinition("JavaDL Options", properties); } } From 71bb95d980039893c7235c9e4e3c6faf7afe2f53 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 24 Jul 2025 16:30:00 +0200 Subject: [PATCH 25/62] Add SymEx strat --- .../ilkd/key/strategy/JavaCardDLStrategy.java | 37 ------ .../ModularJavaDLStrategyFactory.java | 3 +- .../uka/ilkd/key/strategy/SymExStrategy.java | 111 ++++++++++++++++++ .../key/strategy/SymExStrategyFactory.java | 26 ++++ .../de/uka/ilkd/key/proof/rules/javaRules.key | 1 - 5 files changed, 139 insertions(+), 39 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index de82b63ff8..aa539d3660 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -15,7 +15,6 @@ import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.UseDependencyContractRule; import de.uka.ilkd.key.strategy.feature.*; -import de.uka.ilkd.key.strategy.feature.findprefix.FindPrefixRestrictionFeature; import de.uka.ilkd.key.strategy.quantifierHeuristics.ClausesSmallerThanFeature; import de.uka.ilkd.key.strategy.quantifierHeuristics.EliminableQuantifierTF; import de.uka.ilkd.key.strategy.quantifierHeuristics.HeuristicInstantiation; @@ -74,7 +73,6 @@ public class JavaCardDLStrategy extends AbstractFeatureStrategy { protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) { - super(proof); heapLDT = getServices().getTypeConverter().getHeapLDT(); @@ -91,7 +89,6 @@ protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) costComputationF = setupGlobalF(costComputationDispatcher); instantiationF = setupGlobalF(instantiationDispatcher); approvalF = add(setupApprovalF(), approvalDispatcher); - } protected final RuleSetDispatchFeature getCostComputationDispatcher() { @@ -109,7 +106,6 @@ public boolean isResponsibleFor(RuleSet rs) { } protected Feature setupGlobalF(Feature dispatcher) { - final Feature methodSpecF; final String methProp = strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); @@ -299,9 +295,6 @@ private RuleSetDispatchFeature setupCostComputationF() { setupReplaceKnown(d); - bindRuleSet(d, "confluence_restricted", - ifZero(MatchedAssumesFeature.INSTANCE, DiffFindAndIfFeature.INSTANCE)); - setupApplyEq(d, numbers); bindRuleSet(d, "insert_eq_nonrigid", @@ -339,23 +332,6 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "try_apply_subst", add(EqNonDuplicateAppFeature.INSTANCE, longConst(-10000))); - final TermBuffer superFor = new TermBuffer(); - bindRuleSet(d, "split_if", - add(sum(superFor, SuperTermGenerator.upwards(any(), getServices()), - applyTF(superFor, not(ff.program))), longConst(50))); - - final String[] exceptionsWithPenalty = { "java.lang.NullPointerException", - "java.lang.ArrayIndexOutOfBoundsException", "java.lang.ArrayStoreException", - "java.lang.ClassCastException" }; - - bindRuleSet(d, "simplify_prog", - ifZero(ThrownExceptionFeature.create(exceptionsWithPenalty, getServices()), - longConst(500), - ifZero(isBelow(add(ff.forF, not(ff.atom))), longConst(200), longConst(-100)))); - - bindRuleSet(d, "simplify_prog_subset", longConst(-4000)); - bindRuleSet(d, "modal_tautology", longConst(-10000)); - // features influenced by the strategy options boolean useLoopExpand = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) @@ -370,7 +346,6 @@ private RuleSetDispatchFeature setupCostComputationF() { * boolean useBlockExpand = strategyProperties.getProperty( * StrategyProperties.BLOCK_OPTIONS_KEY). equals(StrategyProperties.BLOCK_EXPAND); */ - boolean programsToRight = true; // XXX final String methProp = strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); @@ -447,22 +422,10 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "limitObserver", add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(-200))); - if (programsToRight) { - bindRuleSet(d, "boxDiamondConv", - SumFeature.createSum( - new FindPrefixRestrictionFeature( - FindPrefixRestrictionFeature.PositionModifier.ALLOW_UPDATE_AS_PARENT, - FindPrefixRestrictionFeature.PrefixChecker.ANTEC_POLARITY), - longConst(-1000))); - } else { - bindRuleSet(d, "boxDiamondConv", inftyConst()); - } - bindRuleSet(d, "cut", not(isInstantiated("cutFormula"))); setupUserTaclets(d); - setupSystemInvariantSimp(d); if (quantifierInstantiatedEnabled()) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java index ed92d79688..4b9e72990a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -26,7 +26,8 @@ */ public class ModularJavaDLStrategyFactory implements StrategyFactory { private final List componentFactories = Arrays.asList( - new IntegerStrategyFactory(), new StringStrategyFactory(), new JavaCardDLStrategyFactory()); + new IntegerStrategyFactory(), new StringStrategyFactory(), new SymExStrategyFactory(), + new JavaCardDLStrategyFactory()); /** * The unique {@link Name} of this {@link StrategyFactory}. diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java new file mode 100644 index 0000000000..adb388c849 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -0,0 +1,111 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.feature.DiffFindAndIfFeature; +import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; +import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; +import de.uka.ilkd.key.strategy.feature.ThrownExceptionFeature; +import de.uka.ilkd.key.strategy.feature.findprefix.FindPrefixRestrictionFeature; +import de.uka.ilkd.key.strategy.termProjection.TermBuffer; +import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; + +import org.key_project.logic.Name; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.feature.SumFeature; + +import org.jspecify.annotations.NonNull; + +/// Strategy for symbolic execution rules +public class SymExStrategy extends AbstractFeatureStrategy { + public static final Name NAME = new Name("SymExStrategy"); + + private final FormulaTermFeatures ff; + + public SymExStrategy(Proof proof) { + super(proof); + + var tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); + ff = new FormulaTermFeatures(tf); + } + + private RuleSetDispatchFeature setUpCostComputationF() { + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + boolean programsToRight = true; // XXX + + final String[] exceptionsWithPenalty = { "java.lang.NullPointerException", + "java.lang.ArrayIndexOutOfBoundsException", "java.lang.ArrayStoreException", + "java.lang.ClassCastException" }; + + bindRuleSet(d, "simplify_prog", + ifZero(ThrownExceptionFeature.create(exceptionsWithPenalty, getServices()), + longConst(500), + ifZero(isBelow(add(ff.forF, not(ff.atom))), longConst(200), longConst(-100)))); + + bindRuleSet(d, "simplify_prog_subset", longConst(-4000)); + + bindRuleSet(d, "simplify_expression", -100); + + // simplify + // concrete + // method_expand + // merge_point + + bindRuleSet(d, "modal_tautology", longConst(-10000)); + + if (programsToRight) { + bindRuleSet(d, "boxDiamondConv", + SumFeature.createSum( + new FindPrefixRestrictionFeature( + FindPrefixRestrictionFeature.PositionModifier.ALLOW_UPDATE_AS_PARENT, + FindPrefixRestrictionFeature.PrefixChecker.ANTEC_POLARITY), + longConst(-1000))); + } else { + bindRuleSet(d, "boxDiamondConv", inftyConst()); + } + + bindRuleSet(d, "confluence_restricted", + ifZero(MatchedAssumesFeature.INSTANCE, DiffFindAndIfFeature.INSTANCE)); + + final TermBuffer superFor = new TermBuffer(); + bindRuleSet(d, "split_if", + add(sum(superFor, SuperTermGenerator.upwards(any(), getServices()), + applyTF(superFor, not(ff.program))), longConst(50))); + + return d; + } + + @Override + protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return null; + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return false; + } + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return false; + } + + @Override + public Name name() { + return NAME; + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { + return null; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java new file mode 100644 index 0000000000..2ebcf2530a --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java @@ -0,0 +1,26 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; + +import org.key_project.logic.Name; + +public class SymExStrategyFactory implements StrategyFactory { + @Override + public SymExStrategy create(Proof proof, StrategyProperties strategyProperties) { + return new SymExStrategy(proof); + } + + @Override + public StrategySettingsDefinition getSettingsDefinition() { + return null; + } + + @Override + public Name name() { + return SymExStrategy.NAME; + } +} diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key index 054d8197df..616b27874a 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key @@ -330,7 +330,6 @@ // ---------- rules for array store ---------------// - array_self_reference { \schemaVar \term Heap heapSV; \assumes(wellFormed(heapSV) ==> array = null) From 219f1cee1382fcd5335e6aae12b8a35e67d8b477 Mon Sep 17 00:00:00 2001 From: Drodt Date: Fri, 25 Jul 2025 07:39:27 +0200 Subject: [PATCH 26/62] Finish SymExStrategy --- .../ilkd/key/strategy/JavaCardDLStrategy.java | 117 +------------- .../strategy/JavaCardDLStrategyFactory.java | 126 --------------- .../ModularJavaDLStrategyFactory.java | 2 +- .../uka/ilkd/key/strategy/StringStrategy.java | 4 +- .../uka/ilkd/key/strategy/SymExStrategy.java | 147 ++++++++++++++++-- .../key/strategy/SymExStrategyFactory.java | 115 +++++++++++++- 6 files changed, 254 insertions(+), 257 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index aa539d3660..ee41ced572 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -106,20 +106,6 @@ public boolean isResponsibleFor(RuleSet rs) { } protected Feature setupGlobalF(Feature dispatcher) { - final Feature methodSpecF; - final String methProp = - strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); - switch (methProp) { - case StrategyProperties.METHOD_CONTRACT -> - methodSpecF = methodSpecFeature(longConst(-20)); - case StrategyProperties.METHOD_EXPAND, StrategyProperties.METHOD_NONE -> methodSpecF = - methodSpecFeature(inftyConst()); - default -> { - methodSpecF = null; - assert false; - } - } - final String queryProp = strategyProperties.getProperty(StrategyProperties.QUERY_OPTIONS_KEY); final Feature queryF; @@ -147,65 +133,17 @@ protected Feature setupGlobalF(Feature dispatcher) { depSpecF = ConditionalFeature.createConditional(depFilter, inftyConst()); } - // NOTE (DS, 2019-04-10): The new loop-scope based rules are realized - // as taclets. The strategy settings for those are handled further - // down in this class. - Feature loopInvF; - final String loopProp = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY); - if (loopProp.equals(StrategyProperties.LOOP_INVARIANT)) { - loopInvF = loopInvFeature(longConst(0)); - /* - * NOTE (DS, 2019-04-10): Deactivated the built-in loop scope rule since we now have the - * loop scope taclets which are based on the same theory, but offer several advantages. - */ - // } else if (loopProp.equals(StrategyProperties.LOOP_SCOPE_INVARIANT)) { - // loopInvF = loopInvFeature(inftyConst(), longConst(0)); - } else { - loopInvF = loopInvFeature(inftyConst()); - } - - final Feature blockFeature; - final Feature loopBlockFeature; - final Feature loopBlockApplyHeadFeature; - final String blockProperty = - strategyProperties.getProperty(StrategyProperties.BLOCK_OPTIONS_KEY); - if (blockProperty.equals(StrategyProperties.BLOCK_CONTRACT_INTERNAL)) { - blockFeature = blockContractInternalFeature(longConst(Long.MIN_VALUE)); - loopBlockFeature = loopContractInternalFeature(longConst(Long.MIN_VALUE)); - loopBlockApplyHeadFeature = loopContractApplyHead(longConst(Long.MIN_VALUE)); - } else if (blockProperty.equals(StrategyProperties.BLOCK_CONTRACT_EXTERNAL)) { - blockFeature = blockContractExternalFeature(longConst(Long.MIN_VALUE)); - loopBlockFeature = - SumFeature.createSum(loopContractExternalFeature(longConst(Long.MIN_VALUE)), - loopContractInternalFeature(longConst(42))); - loopBlockApplyHeadFeature = loopContractApplyHead(longConst(Long.MIN_VALUE)); - } else { - blockFeature = blockContractInternalFeature(inftyConst()); - loopBlockFeature = loopContractExternalFeature(inftyConst()); - loopBlockApplyHeadFeature = loopContractApplyHead(inftyConst()); - } - final Feature oneStepSimplificationF = oneStepSimplificationFeature(longConst(-11000)); - final Feature mergeRuleF; - final String mpsProperty = - strategyProperties.getProperty(StrategyProperties.MPS_OPTIONS_KEY); - if (mpsProperty.equals(StrategyProperties.MPS_MERGE)) { - mergeRuleF = mergeRuleFeature(longConst(-4000)); - } else { - mergeRuleF = mergeRuleFeature(inftyConst()); - } - // final Feature smtF = smtFeature(inftyConst()); return SumFeature.createSum( // splitF, // strengthenConstraints, - oneStepSimplificationF, mergeRuleF, + oneStepSimplificationF, // smtF, - methodSpecF, queryF, depSpecF, loopInvF, blockFeature, loopBlockFeature, - loopBlockApplyHeadFeature, dispatcher); + queryF, depSpecF, dispatcher); } private Feature oneStepSimplificationFeature(Feature cost) { @@ -258,9 +196,6 @@ private RuleSetDispatchFeature setupCostComputationF() { // always give infinite cost to obsolete rules bindRuleSet(d, "obsolete", inftyConst()); - // taclets for special invariant handling - bindRuleSet(d, "loopInvariant", -20000); - setupSelectSimplification(d); bindRuleSet(d, "no_self_application", @@ -333,54 +268,11 @@ private RuleSetDispatchFeature setupCostComputationF() { add(EqNonDuplicateAppFeature.INSTANCE, longConst(-10000))); // features influenced by the strategy options - - boolean useLoopExpand = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) - .equals(StrategyProperties.LOOP_EXPAND); - boolean useLoopInvTaclets = - strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) - .equals(StrategyProperties.LOOP_SCOPE_INV_TACLET); - boolean useLoopScopeExpand = - strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) - .equals(StrategyProperties.LOOP_SCOPE_EXPAND); /* * boolean useBlockExpand = strategyProperties.getProperty( * StrategyProperties.BLOCK_OPTIONS_KEY). equals(StrategyProperties.BLOCK_EXPAND); */ - final String methProp = - strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); - - switch (methProp) { - case StrategyProperties.METHOD_CONTRACT -> - /* - * If method treatment by contracts is chosen, this does not mean that method - * expansion - * is disabled. The original cost was 200 and is now increased to 2000 in order to - * repress method expansion stronger when method treatment by contracts is chosen. - */ - bindRuleSet(d, "method_expand", longConst(2000)); - case StrategyProperties.METHOD_EXPAND -> - bindRuleSet(d, "method_expand", longConst(100)); - case StrategyProperties.METHOD_NONE -> bindRuleSet(d, "method_expand", inftyConst()); - default -> throw new RuntimeException("Unexpected strategy property " + methProp); - } - - final String mpsProp = strategyProperties.getProperty(StrategyProperties.MPS_OPTIONS_KEY); - - switch (mpsProp) { - case StrategyProperties.MPS_MERGE -> - /* - * For this case, we use a special feature, since deleting merge points should only - * be - * done after a merge rule application. - */ - bindRuleSet(d, "merge_point", DeleteMergePointRuleFeature.INSTANCE); - case StrategyProperties.MPS_SKIP -> bindRuleSet(d, "merge_point", longConst(-5000)); - case StrategyProperties.MPS_NONE -> bindRuleSet(d, "merge_point", inftyConst()); - default -> throw new RuntimeException("Unexpected strategy property " + methProp); - } - - final String queryAxProp = strategyProperties.getProperty(StrategyProperties.QUERYAXIOM_OPTIONS_KEY); switch (queryAxProp) { @@ -396,10 +288,6 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "classAxiom", inftyConst()); } - bindRuleSet(d, "loop_expand", useLoopExpand ? longConst(0) : inftyConst()); - bindRuleSet(d, "loop_scope_inv_taclet", useLoopInvTaclets ? longConst(0) : inftyConst()); - bindRuleSet(d, "loop_scope_expand", useLoopScopeExpand ? longConst(1000) : inftyConst()); - /* * bindRuleSet ( d, "block_expand", useBlockExpand ? longConst ( 0 ) : inftyConst () ); */ @@ -1004,7 +892,6 @@ protected Feature setupApprovalF() { private RuleSetDispatchFeature setupApprovalDispatcher() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); - final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); bindRuleSet(d, "inReachableStateImplication", NonDuplicateAppModPositionFeature.INSTANCE); bindRuleSet(d, "limitObserver", NonDuplicateAppModPositionFeature.INSTANCE); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index 050b45754e..b490c68691 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java @@ -60,71 +60,6 @@ public class JavaCardDLStrategyFactory implements StrategyFactory { + "proofs even for simple problems. This option can,
" + "nevertheless, be meaningful to keep the complexity
" + "of proofs small and support interactive proving." + ""; - public static final String TOOL_TIP_LOOP_INVARIANT = - "" + "Use loop invariants for loops.
" + "Three properties have to be shown:
" - + "
  • Validity of invariant of a loop is preserved by the
    " - + "loop guard and loop body (initially valid).
  • " - + "
  • If the invariant was valid at the start of the loop, it holds
    " - + "after arbitrarily many loop iterations (body preserves invariant).
  • " - + "
  • Invariant holds after the loop terminates (use case).
  • " + "
"; - public static final String TOOL_TIP_LOOP_SCOPE_INVARIANT = "" - + "Use loop (scope) invariants for loops.
" + "Three properties have to be shown:
" - + "
  • Validity of invariant of a loop is preserved by the
    " - + "loop guard and loop body (initially valid).
  • " - + "
  • If the invariant was valid at the start of the loop, it holds
    " - + "after arbitrarily many loop iterations (body preserves invariant).
  • " - + "
  • Invariant holds after the loop terminates (use case).
  • " + "
" - + "

In the loop scope invariant rule, the last two are combined " - + "into a single goal.
" - + "This rule is easier to comprehend than the traditional rule in " + "the presence of
" - + "potentially exceptional program behavior.

" + ""; - public static final String TOOL_TIP_LOOP_SCOPE_INVARIANT_TACLET = - "" + "Use the loop scope-based invariant taclet, i.e. not the built-in rules.
" - + "Three properties have to be shown:
" - + "
  • Validity of invariant of a loop is preserved by the
    " - + "loop guard and loop body (initially valid).
  • " - + "
  • If the invariant was valid at the start of the loop, it holds
    " - + "after arbitrarily many loop iterations (body preserves invariant).
  • " - + "
  • Invariant holds after the loop terminates (use case).
  • " + "
" - + "

The last two are combined into a single goal or split into two
" - + "goals based on the 'javaLoopTreatment' strategy option.

" + ""; - public static final String TOOL_TIP_LOOP_SCOPE_EXPAND = - "" + "Unroll loop body, but with the loop scope technology.
" - + "This requires less program transformation for irregular
" - + "termination behavior." + ""; - public static final String TOOL_TIP_LOOP_EXPAND = "" + "Unroll loop body." + ""; - public static final String TOOL_TIP_LOOP_NONE = "" + "Leave loops untouched." + ""; - public static final String TOOL_TIP_BLOCK_CONTRACT_INTERNAL = "" - + "Java blocks are replaced by their contracts.
" + "Three properties are shown:" - + "
  • Validity of block contract in the method context
  • " - + "
  • Precondition of contract holds
  • " - + "
  • Postcondition holds after block terminates
  • " + "
" + ""; - public static final String TOOL_TIP_BLOCK_CONTRACT_EXTERNAL = - "" + "Java blocks are replaced by their contracts.
" + "Two properties are shown:" - + "
  • Precondition of contract holds
  • " - + "
  • Postcondition holds after block terminates
  • " + "
"; - public static final String TOOL_TIP_BLOCK_EXPAND = - "" + "Do not use block contracts for Java blocks. Expand Java blocks." + ""; - public static final String TOOL_TIP_METHOD_CONTRACT = - "Replace method calls by contracts. In some cases
" - + "a method call may also be replaced by its method body.
" - + "If query treatment is activated, this behavior applies
" - + "to queries as well."; - public static final String TOOL_TIP_METHOD_EXPAND = - "Replace method calls by their bodies, i.e. by their
" - + "implementation. Method contracts are strictly deactivated."; - public static final String TOOL_TIP_METHOD_NONE = - "" + "Stop when encountering a method" + ""; - public static final String TOOL_TIP_MPS_MERGE = - "Use merge point statements for merging. That is,
" - + "whenever all branches with a given merge point statement
" - + "have reached it, the strategies will eventually merge
" - + "the branches together using the merge point specification."; - public static final String TOOL_TIP_MPS_SKIP = - "Simply removes (skips) the merge point statment;
" - + "no state merging is applied."; - public static final String TOOL_TIP_MPS_NONE = - "" + "Stop when encountering a merge point statement" + ""; public static final String TOOL_TIP_CLASSAXIOM_FREE = "Expand class axioms (such as invariants) freely."; public static final String TOOL_TIP_CLASSAXIOM_DELAYED = @@ -250,61 +185,6 @@ private static OneOfStrategyPropertyDefinition getProofSplitting() { TOOL_TIP_PROOF_SPLITTING_OFF)); } - private static OneOfStrategyPropertyDefinition getLoopTreatment() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.LOOP_OPTIONS_KEY, - "Loop treatment", 2, - /* - * NOTE (DS, 2019-04-10): Deactivated the built-in loop scope rule since we now have the - * loop scope taclets which are based on the same theory, but offer several advantages. - */ - // new StrategyPropertyValueDefinition( - // StrategyProperties.LOOP_SCOPE_INVARIANT, - // "Loop Scope Invariant", TOOL_TIP_LOOP_SCOPE_INVARIANT), - new StrategyPropertyValueDefinition(StrategyProperties.LOOP_SCOPE_INV_TACLET, - "Invariant (Loop Scope)", TOOL_TIP_LOOP_SCOPE_INVARIANT_TACLET), - new StrategyPropertyValueDefinition(StrategyProperties.LOOP_SCOPE_EXPAND, - "Expand (Loop Scope)", TOOL_TIP_LOOP_SCOPE_EXPAND), - new StrategyPropertyValueDefinition(StrategyProperties.LOOP_INVARIANT, - "Invariant (Transformation)", TOOL_TIP_LOOP_INVARIANT), - new StrategyPropertyValueDefinition(StrategyProperties.LOOP_EXPAND, - "Expand (Transformation)", TOOL_TIP_LOOP_EXPAND), - new StrategyPropertyValueDefinition(StrategyProperties.LOOP_NONE, "None", - TOOL_TIP_LOOP_NONE)); - } - - private static OneOfStrategyPropertyDefinition getBlockTreatment() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.BLOCK_OPTIONS_KEY, - "Block treatment", 1, - new StrategyPropertyValueDefinition(StrategyProperties.BLOCK_CONTRACT_INTERNAL, - "Internal Contract", TOOL_TIP_BLOCK_CONTRACT_INTERNAL), - new StrategyPropertyValueDefinition(StrategyProperties.BLOCK_CONTRACT_EXTERNAL, - "External Contract", TOOL_TIP_BLOCK_CONTRACT_EXTERNAL), - new StrategyPropertyValueDefinition(StrategyProperties.BLOCK_EXPAND, "Expand", - TOOL_TIP_BLOCK_EXPAND)); - } - - private static OneOfStrategyPropertyDefinition getMethodTreatment() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.METHOD_OPTIONS_KEY, - "Method treatment", - new StrategyPropertyValueDefinition(StrategyProperties.METHOD_CONTRACT, "Contract", - TOOL_TIP_METHOD_CONTRACT), - new StrategyPropertyValueDefinition(StrategyProperties.METHOD_EXPAND, "Expand", - TOOL_TIP_METHOD_EXPAND), - new StrategyPropertyValueDefinition(StrategyProperties.METHOD_NONE, "None", - TOOL_TIP_METHOD_NONE)); - } - - private static OneOfStrategyPropertyDefinition getMergePointStatementTreatment() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.MPS_OPTIONS_KEY, - "Merge point statements", - new StrategyPropertyValueDefinition(StrategyProperties.MPS_MERGE, "Merge", - TOOL_TIP_MPS_MERGE), - new StrategyPropertyValueDefinition(StrategyProperties.MPS_SKIP, "Skip", - TOOL_TIP_MPS_SKIP), - new StrategyPropertyValueDefinition(StrategyProperties.MPS_NONE, "None", - TOOL_TIP_MPS_NONE)); - } - private static OneOfStrategyPropertyDefinition getDependencyContracts() { return new OneOfStrategyPropertyDefinition(StrategyProperties.DEP_OPTIONS_KEY, "Dependency contracts", @@ -383,11 +263,6 @@ public StrategySettingsDefinition getSettingsDefinition() { // Properties final OneOfStrategyPropertyDefinition ossUsage = getOssUsage(); final OneOfStrategyPropertyDefinition proofSplitting = getProofSplitting(); - final OneOfStrategyPropertyDefinition loopTreatment = getLoopTreatment(); - final OneOfStrategyPropertyDefinition blockTreatment = getBlockTreatment(); - final OneOfStrategyPropertyDefinition methodTreatment = getMethodTreatment(); - final OneOfStrategyPropertyDefinition mergePointStatementTreatment = - getMergePointStatementTreatment(); final OneOfStrategyPropertyDefinition dependencyContracts = getDependencyContracts(); final OneOfStrategyPropertyDefinition queryTreatment = getQueryTreatment(); final OneOfStrategyPropertyDefinition quantifierTreatment = getQuantifierTreatment(); @@ -395,7 +270,6 @@ public StrategySettingsDefinition getSettingsDefinition() { final OneOfStrategyPropertyDefinition autoInduction = getAutoInduction(); // Model return new StrategySettingsDefinition("Java DL Options", ossUsage, proofSplitting, - loopTreatment, blockTreatment, methodTreatment, mergePointStatementTreatment, dependencyContracts, queryTreatment, quantifierTreatment, classAxiom, autoInduction); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java index 4b9e72990a..b5546bcf64 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -26,7 +26,7 @@ */ public class ModularJavaDLStrategyFactory implements StrategyFactory { private final List componentFactories = Arrays.asList( - new IntegerStrategyFactory(), new StringStrategyFactory(), new SymExStrategyFactory(), + new IntegerStrategyFactory(), new SymExStrategyFactory(), new StringStrategyFactory(), new JavaCardDLStrategyFactory()); /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index 42b2069108..777d986a34 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -157,8 +157,8 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return !(NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, - new MutableState()) == TopRuleAppCost.INSTANCE); + return NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, + new MutableState()) != TopRuleAppCost.INSTANCE; } @Override diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index adb388c849..ee2b9bc1d9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -5,10 +5,7 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; -import de.uka.ilkd.key.strategy.feature.DiffFindAndIfFeature; -import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; -import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; -import de.uka.ilkd.key.strategy.feature.ThrownExceptionFeature; +import de.uka.ilkd.key.strategy.feature.*; import de.uka.ilkd.key.strategy.feature.findprefix.FindPrefixRestrictionFeature; import de.uka.ilkd.key.strategy.termProjection.TermBuffer; import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; @@ -19,6 +16,8 @@ import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.TopRuleAppCost; +import org.key_project.prover.strategy.costbased.feature.Feature; import org.key_project.prover.strategy.costbased.feature.SumFeature; import org.jspecify.annotations.NonNull; @@ -29,14 +28,97 @@ public class SymExStrategy extends AbstractFeatureStrategy { private final FormulaTermFeatures ff; - public SymExStrategy(Proof proof) { + private final StrategyProperties strategyProperties; + + private final RuleSetDispatchFeature costComputationDispatcher; + private final Feature costComputationF; + private final RuleSetDispatchFeature approvalDispatcher; + private final Feature approvalF; + private final RuleSetDispatchFeature instantiationDispatcher; + private final Feature instantiationF; + + public SymExStrategy(Proof proof, StrategyProperties strategyProperties) { super(proof); + this.strategyProperties = strategyProperties; var tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); ff = new FormulaTermFeatures(tf); + + costComputationDispatcher = setupCostComputationF(); + // TODO: necessary? + approvalDispatcher = new RuleSetDispatchFeature(); + instantiationDispatcher = new RuleSetDispatchFeature(); + + costComputationF = setupGlobalF(costComputationDispatcher); + instantiationF = setupGlobalF(instantiationDispatcher); + approvalF = NonDuplicateAppFeature.INSTANCE; + } + + private Feature setupGlobalF(Feature dispatcher) { + final Feature methodSpecF; + final String methProp = + strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); + switch (methProp) { + case StrategyProperties.METHOD_CONTRACT -> methodSpecF = methodSpecFeature(longConst(-20)); + case StrategyProperties.METHOD_EXPAND, StrategyProperties.METHOD_NONE -> methodSpecF = + methodSpecFeature(inftyConst()); + default -> { + methodSpecF = null; + assert false; + } + } + + // NOTE (DS, 2019-04-10): The new loop-scope based rules are realized + // as taclets. The strategy settings for those are handled further + // down in this class. + Feature loopInvF; + final String loopProp = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY); + if (loopProp.equals(StrategyProperties.LOOP_INVARIANT)) { + loopInvF = loopInvFeature(longConst(0)); + /* + * NOTE (DS, 2019-04-10): Deactivated the built-in loop scope rule since we now have the + * loop scope taclets which are based on the same theory, but offer several advantages. + */ + // } else if (loopProp.equals(StrategyProperties.LOOP_SCOPE_INVARIANT)) { + // loopInvF = loopInvFeature(inftyConst(), longConst(0)); + } else { + loopInvF = loopInvFeature(inftyConst()); + } + + final Feature blockFeature; + final Feature loopBlockFeature; + final Feature loopBlockApplyHeadFeature; + final String blockProperty = + strategyProperties.getProperty(StrategyProperties.BLOCK_OPTIONS_KEY); + if (blockProperty.equals(StrategyProperties.BLOCK_CONTRACT_INTERNAL)) { + blockFeature = blockContractInternalFeature(longConst(Long.MIN_VALUE)); + loopBlockFeature = loopContractInternalFeature(longConst(Long.MIN_VALUE)); + loopBlockApplyHeadFeature = loopContractApplyHead(longConst(Long.MIN_VALUE)); + } else if (blockProperty.equals(StrategyProperties.BLOCK_CONTRACT_EXTERNAL)) { + blockFeature = blockContractExternalFeature(longConst(Long.MIN_VALUE)); + loopBlockFeature = + SumFeature.createSum(loopContractExternalFeature(longConst(Long.MIN_VALUE)), + loopContractInternalFeature(longConst(42))); + loopBlockApplyHeadFeature = loopContractApplyHead(longConst(Long.MIN_VALUE)); + } else { + blockFeature = blockContractInternalFeature(inftyConst()); + loopBlockFeature = loopContractExternalFeature(inftyConst()); + loopBlockApplyHeadFeature = loopContractApplyHead(inftyConst()); + } + + final Feature mergeRuleF; + final String mpsProperty = + strategyProperties.getProperty(StrategyProperties.MPS_OPTIONS_KEY); + if (mpsProperty.equals(StrategyProperties.MPS_MERGE)) { + mergeRuleF = mergeRuleFeature(longConst(-4000)); + } else { + mergeRuleF = mergeRuleFeature(inftyConst()); + } + return SumFeature.createSum(mergeRuleF, methodSpecF, loopInvF, blockFeature, + loopBlockFeature, loopBlockApplyHeadFeature, dispatcher); } - private RuleSetDispatchFeature setUpCostComputationF() { + private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); boolean programsToRight = true; // XXX @@ -55,8 +137,51 @@ private RuleSetDispatchFeature setUpCostComputationF() { // simplify // concrete - // method_expand - // merge_point + + // taclets for special invariant handling + bindRuleSet(d, "loopInvariant", -20000); + + boolean useLoopExpand = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) + .equals(StrategyProperties.LOOP_EXPAND); + boolean useLoopInvTaclets = + strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) + .equals(StrategyProperties.LOOP_SCOPE_INV_TACLET); + boolean useLoopScopeExpand = + strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY) + .equals(StrategyProperties.LOOP_SCOPE_EXPAND); + + bindRuleSet(d, "loop_expand", useLoopExpand ? longConst(0) : inftyConst()); + bindRuleSet(d, "loop_scope_inv_taclet", useLoopInvTaclets ? longConst(0) : inftyConst()); + bindRuleSet(d, "loop_scope_expand", useLoopScopeExpand ? longConst(1000) : inftyConst()); + + + final String methProp = + strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); + switch (methProp) { + case StrategyProperties.METHOD_CONTRACT -> + /* + * If method treatment by contracts is chosen, this does not mean that method expansion + * is disabled. The original cost was 200 and is now increased to 2000 in order to + * repress method expansion stronger when method treatment by contracts is chosen. + */ + bindRuleSet(d, "method_expand", longConst(2000)); + case StrategyProperties.METHOD_EXPAND -> bindRuleSet(d, "method_expand", longConst(100)); + case StrategyProperties.METHOD_NONE -> bindRuleSet(d, "method_expand", inftyConst()); + default -> throw new RuntimeException("Unexpected strategy property " + methProp); + } + + final String mpsProp = strategyProperties.getProperty(StrategyProperties.MPS_OPTIONS_KEY); + switch (mpsProp) { + case StrategyProperties.MPS_MERGE -> + /* + * For this case, we use a special feature, since deleting merge points should only be + * done after a merge rule application. + */ + bindRuleSet(d, "merge_point", DeleteMergePointRuleFeature.INSTANCE); + case StrategyProperties.MPS_SKIP -> bindRuleSet(d, "merge_point", longConst(-5000)); + case StrategyProperties.MPS_NONE -> bindRuleSet(d, "merge_point", inftyConst()); + default -> throw new RuntimeException("Unexpected strategy property " + mpsProp); + } bindRuleSet(d, "modal_tautology", longConst(-10000)); @@ -85,7 +210,7 @@ private RuleSetDispatchFeature setUpCostComputationF() { @Override protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { - return null; + return instantiationF.computeCost(app, pio, goal, mState); } @Override @@ -95,7 +220,7 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return false; + return approvalF.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; } @Override @@ -106,6 +231,6 @@ public Name name() { @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { - return null; + return costComputationF.computeCost(app, pos, goal, mState); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java index 2ebcf2530a..51d6ebc3b8 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java @@ -4,19 +4,130 @@ package de.uka.ilkd.key.strategy; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.OneOfStrategyPropertyDefinition; +import de.uka.ilkd.key.strategy.definition.StrategyPropertyValueDefinition; import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; import org.key_project.logic.Name; public class SymExStrategyFactory implements StrategyFactory { + public static final String TOOL_TIP_LOOP_INVARIANT = + "" + "Use loop invariants for loops.
" + "Three properties have to be shown:
" + + "
  • Validity of invariant of a loop is preserved by the
    " + + "loop guard and loop body (initially valid).
  • " + + "
  • If the invariant was valid at the start of the loop, it holds
    " + + "after arbitrarily many loop iterations (body preserves invariant).
  • " + + "
  • Invariant holds after the loop terminates (use case).
  • " + "
"; + public static final String TOOL_TIP_LOOP_SCOPE_INVARIANT_TACLET = + "" + "Use the loop scope-based invariant taclet, i.e. not the built-in rules.
" + + "Three properties have to be shown:
" + + "
  • Validity of invariant of a loop is preserved by the
    " + + "loop guard and loop body (initially valid).
  • " + + "
  • If the invariant was valid at the start of the loop, it holds
    " + + "after arbitrarily many loop iterations (body preserves invariant).
  • " + + "
  • Invariant holds after the loop terminates (use case).
  • " + "
" + + "

The last two are combined into a single goal or split into two
" + + "goals based on the 'javaLoopTreatment' strategy option.

" + ""; + public static final String TOOL_TIP_LOOP_SCOPE_EXPAND = + "" + "Unroll loop body, but with the loop scope technology.
" + + "This requires less program transformation for irregular
" + + "termination behavior." + ""; + public static final String TOOL_TIP_LOOP_EXPAND = "" + "Unroll loop body." + ""; + public static final String TOOL_TIP_LOOP_NONE = "" + "Leave loops untouched." + ""; + public static final String TOOL_TIP_BLOCK_CONTRACT_INTERNAL = "" + + "Java blocks are replaced by their contracts.
" + "Three properties are shown:" + + "
  • Validity of block contract in the method context
  • " + + "
  • Precondition of contract holds
  • " + + "
  • Postcondition holds after block terminates
  • " + "
" + ""; + public static final String TOOL_TIP_BLOCK_CONTRACT_EXTERNAL = + "" + "Java blocks are replaced by their contracts.
" + "Two properties are shown:" + + "
  • Precondition of contract holds
  • " + + "
  • Postcondition holds after block terminates
  • " + "
"; + public static final String TOOL_TIP_BLOCK_EXPAND = + "" + "Do not use block contracts for Java blocks. Expand Java blocks." + ""; + public static final String TOOL_TIP_METHOD_CONTRACT = + "Replace method calls by contracts. In some cases
" + + "a method call may also be replaced by its method body.
" + + "If query treatment is activated, this behavior applies
" + + "to queries as well."; + public static final String TOOL_TIP_METHOD_EXPAND = + "Replace method calls by their bodies, i.e. by their
" + + "implementation. Method contracts are strictly deactivated."; + public static final String TOOL_TIP_METHOD_NONE = + "" + "Stop when encountering a method" + ""; + public static final String TOOL_TIP_MPS_MERGE = + "Use merge point statements for merging. That is,
" + + "whenever all branches with a given merge point statement
" + + "have reached it, the strategies will eventually merge
" + + "the branches together using the merge point specification."; + public static final String TOOL_TIP_MPS_SKIP = + "Simply removes (skips) the merge point statment;
" + + "no state merging is applied."; + public static final String TOOL_TIP_MPS_NONE = + "" + "Stop when encountering a merge point statement" + ""; + @Override public SymExStrategy create(Proof proof, StrategyProperties strategyProperties) { - return new SymExStrategy(proof); + return new SymExStrategy(proof, strategyProperties); + } + + private static OneOfStrategyPropertyDefinition getLoopTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.LOOP_OPTIONS_KEY, + "Loop treatment", 2, + new StrategyPropertyValueDefinition(StrategyProperties.LOOP_SCOPE_INV_TACLET, + "Invariant (Loop Scope)", TOOL_TIP_LOOP_SCOPE_INVARIANT_TACLET), + new StrategyPropertyValueDefinition(StrategyProperties.LOOP_SCOPE_EXPAND, + "Expand (Loop Scope)", TOOL_TIP_LOOP_SCOPE_EXPAND), + new StrategyPropertyValueDefinition(StrategyProperties.LOOP_INVARIANT, + "Invariant (Transformation)", TOOL_TIP_LOOP_INVARIANT), + new StrategyPropertyValueDefinition(StrategyProperties.LOOP_EXPAND, + "Expand (Transformation)", TOOL_TIP_LOOP_EXPAND), + new StrategyPropertyValueDefinition(StrategyProperties.LOOP_NONE, "None", + TOOL_TIP_LOOP_NONE)); + } + + private static OneOfStrategyPropertyDefinition getBlockTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.BLOCK_OPTIONS_KEY, + "Block treatment", 1, + new StrategyPropertyValueDefinition(StrategyProperties.BLOCK_CONTRACT_INTERNAL, + "Internal Contract", TOOL_TIP_BLOCK_CONTRACT_INTERNAL), + new StrategyPropertyValueDefinition(StrategyProperties.BLOCK_CONTRACT_EXTERNAL, + "External Contract", TOOL_TIP_BLOCK_CONTRACT_EXTERNAL), + new StrategyPropertyValueDefinition(StrategyProperties.BLOCK_EXPAND, "Expand", + TOOL_TIP_BLOCK_EXPAND)); + } + + private static OneOfStrategyPropertyDefinition getMethodTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.METHOD_OPTIONS_KEY, + "Method treatment", + new StrategyPropertyValueDefinition(StrategyProperties.METHOD_CONTRACT, "Contract", + TOOL_TIP_METHOD_CONTRACT), + new StrategyPropertyValueDefinition(StrategyProperties.METHOD_EXPAND, "Expand", + TOOL_TIP_METHOD_EXPAND), + new StrategyPropertyValueDefinition(StrategyProperties.METHOD_NONE, "None", + TOOL_TIP_METHOD_NONE)); + } + + private static OneOfStrategyPropertyDefinition getMergePointStatementTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.MPS_OPTIONS_KEY, + "Merge point statements", + new StrategyPropertyValueDefinition(StrategyProperties.MPS_MERGE, "Merge", + TOOL_TIP_MPS_MERGE), + new StrategyPropertyValueDefinition(StrategyProperties.MPS_SKIP, "Skip", + TOOL_TIP_MPS_SKIP), + new StrategyPropertyValueDefinition(StrategyProperties.MPS_NONE, "None", + TOOL_TIP_MPS_NONE)); } @Override public StrategySettingsDefinition getSettingsDefinition() { - return null; + final OneOfStrategyPropertyDefinition loopTreatment = getLoopTreatment(); + final OneOfStrategyPropertyDefinition blockTreatment = getBlockTreatment(); + final OneOfStrategyPropertyDefinition methodTreatment = getMethodTreatment(); + final OneOfStrategyPropertyDefinition mergePointStatementTreatment = + getMergePointStatementTreatment(); + return new StrategySettingsDefinition("Symbolic Execution Options", + loopTreatment, blockTreatment, methodTreatment, mergePointStatementTreatment); } @Override From 2fd419c29589611493cfd021721605d5f815e325 Mon Sep 17 00:00:00 2001 From: Drodt Date: Fri, 25 Jul 2025 11:26:45 +0200 Subject: [PATCH 27/62] Split program rules from normal rule sets --- .../uka/ilkd/key/strategy/SymExStrategy.java | 27 +++++++----- .../de/uka/ilkd/key/proof/rules/javaRules.key | 44 +++++++++---------- .../key/proof/rules/ruleSetsDeclarations.key | 2 + 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index ee2b9bc1d9..a81c0aa678 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -13,11 +13,14 @@ import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; import org.key_project.prover.strategy.costbased.TopRuleAppCost; import org.key_project.prover.strategy.costbased.feature.Feature; +import org.key_project.prover.strategy.costbased.feature.FindDepthFeature; +import org.key_project.prover.strategy.costbased.feature.ScaleFeature; import org.key_project.prover.strategy.costbased.feature.SumFeature; import org.jspecify.annotations.NonNull; @@ -54,6 +57,12 @@ public SymExStrategy(Proof proof, StrategyProperties strategyProperties) { approvalF = NonDuplicateAppFeature.INSTANCE; } + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null + || approvalDispatcher.get(rs) != null; + } + private Feature setupGlobalF(Feature dispatcher) { final Feature methodSpecF; final String methProp = @@ -68,19 +77,10 @@ private Feature setupGlobalF(Feature dispatcher) { } } - // NOTE (DS, 2019-04-10): The new loop-scope based rules are realized - // as taclets. The strategy settings for those are handled further - // down in this class. Feature loopInvF; final String loopProp = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY); if (loopProp.equals(StrategyProperties.LOOP_INVARIANT)) { loopInvF = loopInvFeature(longConst(0)); - /* - * NOTE (DS, 2019-04-10): Deactivated the built-in loop scope rule since we now have the - * loop scope taclets which are based on the same theory, but offer several advantages. - */ - // } else if (loopProp.equals(StrategyProperties.LOOP_SCOPE_INVARIANT)) { - // loopInvF = loopInvFeature(inftyConst(), longConst(0)); } else { loopInvF = loopInvFeature(inftyConst()); } @@ -135,8 +135,13 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "simplify_expression", -100); - // simplify - // concrete + bindRuleSet(d, "simplify_java", -4500); + + final Feature findDepthFeature = + FindDepthFeature.getInstance(); + bindRuleSet(d, "concrete", + add(longConst(-11000), + ScaleFeature.createScaled(findDepthFeature, 10.0))); // taclets for special invariant handling bindRuleSet(d, "loopInvariant", -20000); diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key index 616b27874a..09d1a9eb79 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key @@ -336,7 +336,7 @@ \find(arrayStoreValid(array, G::select(heapSV, array, arr(idx)))) \sameUpdateLevel \replacewith(true) - \heuristics(simplify) + \heuristics(simplify_java) }; // author: scheben; correctness proven in KeY for G = Object @@ -347,7 +347,7 @@ \find(arrayStoreValid(array, EQ)) \sameUpdateLevel \replacewith(true) - \heuristics(simplify) + \heuristics(simplify_java) }; null_can_always_be_stored_in_a_reference_type_array { @@ -356,14 +356,14 @@ \sameUpdateLevel \varcond(\isReferenceArray(array)) \replacewith(true) - \heuristics(simplify) + \heuristics(simplify_java) }; /* array_store_known_dynamic_array_type_prim { \find (arrayStoreValid(G::(idx), vint_val)) \varcond(\isReference(G)) \replacewith(#arrayBaseInstanceOf(G::(idx), vint_val) = TRUE) - \heuristics(simplify) + \heuristics(simplify_java) \displayname "known dynamic array type" }; */ @@ -375,7 +375,7 @@ \varcond(\isReference [non_null](J)) \replacewith(obj = null | #arrayBaseInstanceOf(J::exactInstance(array), obj) = TRUE) - \heuristics(simplify) + \heuristics(simplify_java) \displayname "known dynamic array type" }; @@ -1340,52 +1340,52 @@ ifEnterThen { \find(\modality{#allmodal}{.. #loc=true; if (#loc) #s0 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. #loc=true; #s0 ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) }; ifSkipThen { \find(\modality{#allmodal}{.. #loc=false; if (#loc) #s0 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. #loc=false; ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) }; ifElseSkipElse { \find(\modality{#allmodal}{.. #loc=true; if (#loc) #s0 else #s1 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. #loc=true; #s0 ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) }; ifElseSkipThen { \find(\modality{#allmodal}{.. #loc=false; if (#loc) #s0 else #s1 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. #loc=false; #s1 ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) }; ifEnterThenConditionInBlock { \find(\modality{#allmodal}{.. { #loc=true; } if (#loc) #s0 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. { #loc=true; } #s0 ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) \displayname "ifEnterThen" }; ifSkipThenConditionInBlock { \find(\modality{#allmodal}{.. { #loc=false; } if (#loc) #s0 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. { #loc=false; } ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) \displayname "ifSkipThen" }; ifElseSkipElseConditionInBlock { \find(\modality{#allmodal}{.. { #loc=true;} if (#loc) #s0 else #s1 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. { #loc=true;} #s0 ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) \displayname "ifElseSkipElse" }; ifElseSkipThenConditionInBlock { \find(\modality{#allmodal}{.. { #loc=false; } if (#loc) #s0 else #s1 ...}\endmodality (post)) \replacewith(\modality{#allmodal}{.. { #loc=false; } #s1 ...}\endmodality (post)) - \heuristics(simplify) + \heuristics(simplify_java) \displayname "ifElseSkipThen" }; @@ -1521,7 +1521,7 @@ insert_constant_value { \find(#cv) \replacewith(#constantvalue(#cv)) - \heuristics(concrete) + \heuristics(concrete_java) }; // ------------------------------------------------------------------------ @@ -4054,7 +4054,7 @@ \find(boolean::select(heap, null, alphaObj::)) \sameUpdateLevel \replacewith(TRUE) - \heuristics(confluence_restricted, simplify) + \heuristics(confluence_restricted, simplify_java) \displayname "initialized classes have been prepared" }; @@ -4063,7 +4063,7 @@ \find(boolean::select(heap, null, alphaObj::)) \sameUpdateLevel \replacewith(TRUE) - \heuristics(confluence_restricted, simplify) + \heuristics(confluence_restricted, simplify_java) \displayname "classes being initialized have been prepared" }; @@ -4072,7 +4072,7 @@ \find(boolean::select(heap, null, alphaObj::)) \sameUpdateLevel \replacewith(FALSE) - \heuristics(confluence_restricted, simplify) + \heuristics(confluence_restricted, simplify_java) \displayname "initialized class is not erroneous" }; @@ -4081,7 +4081,7 @@ \find(boolean::select(heap, null, alphaObj::)) \sameUpdateLevel \replacewith(FALSE) - \heuristics(confluence_restricted, simplify) + \heuristics(confluence_restricted, simplify_java) \displayname "initialisation process has already terminated" }; @@ -4090,7 +4090,7 @@ \find(boolean::select(heap, null, alphaObj::)) \sameUpdateLevel \replacewith(FALSE) - \heuristics(confluence_restricted, simplify) + \heuristics(confluence_restricted, simplify_java) \displayname "initialization process has already terminated (or never begun)" }; @@ -4100,7 +4100,7 @@ \sameUpdateLevel \varcond(\sub(betaObj, alphaObj)) \replacewith(FALSE) - \heuristics(confluence_restricted, simplify) + \heuristics(confluence_restricted, simplify_java) \displayname "erroneous classes have no initialized subclasses" }; @@ -4110,7 +4110,7 @@ \sameUpdateLevel \varcond(\isReference [non_null](betaObj), \strict \sub(betaObj, alphaObj)) \replacewith(TRUE) - \heuristics(simplify) + \heuristics(simplify_java) }; superclasses_of_initialized_classes_are_prepared { @@ -4119,6 +4119,6 @@ \sameUpdateLevel \varcond(\sub(betaObj, alphaObj)) \replacewith(TRUE) - \heuristics(simplify) + \heuristics(simplify_java) }; } diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key index 427c6ca142..e4734b8edc 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key @@ -24,6 +24,8 @@ modal_tautology; simplify_prog; + simplify_java; + concrete_java; // updates update_elim; From 9f3ae8b9b665c0f612b8d193b2edd377c4ccfec4 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 30 Jul 2025 09:34:31 +0200 Subject: [PATCH 28/62] Simplify --- .../java/de/uka/ilkd/key/strategy/SymExStrategy.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index a81c0aa678..7ce66c491f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -35,8 +35,6 @@ public class SymExStrategy extends AbstractFeatureStrategy { private final RuleSetDispatchFeature costComputationDispatcher; private final Feature costComputationF; - private final RuleSetDispatchFeature approvalDispatcher; - private final Feature approvalF; private final RuleSetDispatchFeature instantiationDispatcher; private final Feature instantiationF; @@ -48,19 +46,15 @@ public SymExStrategy(Proof proof, StrategyProperties strategyProperties) { ff = new FormulaTermFeatures(tf); costComputationDispatcher = setupCostComputationF(); - // TODO: necessary? - approvalDispatcher = new RuleSetDispatchFeature(); instantiationDispatcher = new RuleSetDispatchFeature(); costComputationF = setupGlobalF(costComputationDispatcher); instantiationF = setupGlobalF(instantiationDispatcher); - approvalF = NonDuplicateAppFeature.INSTANCE; } @Override public boolean isResponsibleFor(RuleSet rs) { - return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null - || approvalDispatcher.get(rs) != null; + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; } private Feature setupGlobalF(Feature dispatcher) { @@ -139,7 +133,7 @@ private RuleSetDispatchFeature setupCostComputationF() { final Feature findDepthFeature = FindDepthFeature.getInstance(); - bindRuleSet(d, "concrete", + bindRuleSet(d, "concrete_java", add(longConst(-11000), ScaleFeature.createScaled(findDepthFeature, 10.0))); @@ -225,7 +219,7 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return approvalF.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; + return true; } @Override From 7988fb5efebaa59744ba983273d0c70bab92f1aa Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 30 Jul 2025 09:42:22 +0200 Subject: [PATCH 29/62] Modularize int assign rules --- .../java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java | 3 --- .../src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index ee41ced572..b21d449e23 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -184,9 +184,6 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "simplify", -4500); bindRuleSet(d, "simplify_enlarging", -2000); bindRuleSet(d, "simplify_ENLARGING", -1900); - bindRuleSet(d, "simplify_expression", -100); - bindRuleSet(d, "executeIntegerAssignment", -100); - bindRuleSet(d, "executeDoubleAssignment", -100); bindRuleSet(d, "simplify_int", inftyConst()); bindRuleSet(d, "javaIntegerSemantics", diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index 7ce66c491f..ef485c41c4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -17,7 +17,6 @@ import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; -import org.key_project.prover.strategy.costbased.TopRuleAppCost; import org.key_project.prover.strategy.costbased.feature.Feature; import org.key_project.prover.strategy.costbased.feature.FindDepthFeature; import org.key_project.prover.strategy.costbased.feature.ScaleFeature; @@ -131,6 +130,9 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "simplify_java", -4500); + bindRuleSet(d, "executeIntegerAssignment", -100); + bindRuleSet(d, "executeDoubleAssignment", -100); + final Feature findDepthFeature = FindDepthFeature.getInstance(); bindRuleSet(d, "concrete_java", From 7c5f40f3d3dc3690c35ee22a1a6fae8748d43e30 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 30 Jul 2025 10:56:40 +0200 Subject: [PATCH 30/62] Conflict resolution --- ...repareInfFlowContractPreBranchesMacro.java | 7 ++- .../key/strategy/AbstractFeatureStrategy.java | 2 + .../ilkd/key/strategy/IntegerStrategy.java | 9 +++ .../ilkd/key/strategy/JavaCardDLStrategy.java | 10 ++-- .../key/strategy/ModularJavaDLStrategy.java | 55 ++++++++++++++++++- .../uka/ilkd/key/strategy/StringStrategy.java | 5 ++ .../uka/ilkd/key/strategy/SymExStrategy.java | 5 ++ .../feature/RuleSetDispatchFeature.java | 15 +++++ 8 files changed, 101 insertions(+), 7 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java b/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java index bf7b94b1a0..fefab75a73 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java @@ -10,6 +10,7 @@ import de.uka.ilkd.key.strategy.AbstractFeatureStrategy; import de.uka.ilkd.key.strategy.Strategy; import de.uka.ilkd.key.strategy.feature.FocusIsSubFormulaOfInfFlowContractAppFeature; +import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -148,6 +149,10 @@ protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal public boolean isStopAtFirstNonCloseableGoal() { return false; } - } + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return new RuleSetDispatchFeature(); + } + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java index 612cf51c92..31f1d8a753 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java @@ -202,4 +202,6 @@ protected Feature instantiateTriggeredVariable(ProjectionToTerm value) { protected Feature instantiate(String sv, ProjectionToTerm value) { return instantiate(new Name(sv), value); } + + protected abstract RuleSetDispatchFeature getCostDispatcher(); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 3d1f5e2706..2aa10da06b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -147,6 +147,10 @@ private RuleSetDispatchFeature setupCostComputationF() { setupDefOpsPrimaryCategories(d); + bindRuleSet(d, "order_terms", + add(applyTF("commEqRight", tf.monomial), applyTF("commEqLeft", tf.polynomial), + monSmallerThan("commEqLeft", "commEqRight", numbers), longConst(-5000))); + // For taclets that need instantiation, but where the instantiation is // deterministic and does not have to be repeated at a later point, we // setup the same feature terms as in the instantiation method. The @@ -969,4 +973,9 @@ public Name name() { PosInOccurrence pos, Goal goal, MutableState mState) { return this.costComputationDispatcher.computeCost(app, pos, goal, mState); } + + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return costComputationDispatcher; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index b21d449e23..18ed412b90 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -233,10 +233,7 @@ private RuleSetDispatchFeature setupCostComputationF() { applyTF(FocusProjection.create(0), IsNonRigidTermFeature.INSTANCE)); bindRuleSet(d, "order_terms", - add(ifZero(applyTF("commEqLeft", tf.intF), - add(applyTF("commEqRight", tf.monomial), applyTF("commEqLeft", tf.polynomial), - monSmallerThan("commEqLeft", "commEqRight", numbers)), - termSmallerThan("commEqLeft", "commEqRight")), longConst(-5000))); + add(termSmallerThan("commEqLeft", "commEqRight"), longConst(-5000))); bindRuleSet(d, "simplify_literals", // ifZero ( ConstraintStrengthenFeatureUC.create(proof), @@ -1069,4 +1066,9 @@ public boolean isStopAtFirstNonCloseableGoal() { return strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) .equals(StrategyProperties.STOPMODE_NONCLOSE); } + + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return costComputationDispatcher; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 4b9df1d0c5..a565317a46 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -4,6 +4,7 @@ package de.uka.ilkd.key.strategy; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; @@ -13,10 +14,12 @@ import de.uka.ilkd.key.strategy.feature.AgeFeature; import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; import de.uka.ilkd.key.strategy.feature.NonDuplicateAppFeature; +import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.NumberRuleAppCost; @@ -34,6 +37,8 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final StrategyProperties strategyProperties; private final Feature reduceCostTillMaxF; private final Feature reduceInstTillMaxF; + private final ArithTermFeatures tf; + private final RuleSetDispatchFeature conflictCostDispatcher; public ModularJavaDLStrategy(Proof proof, List componentStrategies, StrategyProperties properties) { @@ -42,6 +47,51 @@ public ModularJavaDLStrategy(Proof proof, List componen reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost); reduceInstTillMaxF = new ReduceTillMaxFeature(AbstractFeatureStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); + this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); + conflictCostDispatcher = resolveConflicts(); + } + + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return null; + } + + private record StratAndDispatcher(AbstractFeatureStrategy strategy, + RuleSetDispatchFeature dispatcher) { + } + + private RuleSetDispatchFeature resolveConflicts() { + var dis = new RuleSetDispatchFeature(); + var dispatchers = + strategies.stream().map(s -> new StratAndDispatcher(s, s.getCostDispatcher())).toList(); + var map = new HashMap>(); + for (var d : dispatchers) { + var s = d.strategy; + for (var rs : d.dispatcher.ruleSets()) { + var lst = map.computeIfAbsent(rs, r -> new ArrayList<>()); + lst.add(s); + } + } + for (var e : map.entrySet()) { + if (e.getValue().size() > 1) { + resolveConflict(dis, e.getKey(), e.getValue()); + } + } + return dis; + } + + private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, + List value) { + switch (rs.name().toString()) { + case "order_terms" -> { + var intStrat = value.getFirst(); + var javaDLStrat = value.get(1); + bindRuleSet(d, "order_terms", + ifZero(applyTF("commEqLeft", tf.intF), + intStrat.getCostDispatcher().remove(rs), + javaDLStrat.getCostDispatcher().remove(rs))); + } + } } @Override @@ -78,7 +128,7 @@ public Name name() { } private R reduceTillMax(RuleApp app, R init, R max, BiFunction accumulator, - Function mapper) { + Function mapper, Object... conflict) { for (AbstractFeatureStrategy strategy : strategies) { var isResponsible = false; var ruleSets = app.rule().ruleSets(); @@ -108,9 +158,10 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + // TODO: This could be inefficient. Maybe we can simplify conflict resolution Feature totalCost = add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, - reduceCostTillMaxF, + reduceCostTillMaxF, conflictCostDispatcher, AgeFeature.INSTANCE, ifMatchedF); return totalCost.computeCost(app, pos, goal, mState); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index 777d986a34..bf212d867b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -177,4 +177,9 @@ public Name name() { PosInOccurrence pos, Goal goal, MutableState mState) { return this.costComputationDispatcher.computeCost(app, pos, goal, mState); } + + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return costComputationDispatcher; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index ef485c41c4..556cde7377 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -234,4 +234,9 @@ public Name name() { PosInOccurrence pos, GOAL goal, MutableState mState) { return costComputationF.computeCost(app, pos, goal, mState); } + + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return costComputationDispatcher; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java index 2040af28e8..f51c116ae1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java @@ -33,6 +33,10 @@ public class RuleSetDispatchFeature implements Feature { private final Map rulesetToFeature = new LinkedHashMap<>(); + public Iterable ruleSets() { + return rulesetToFeature.keySet(); + } + @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, Goal goal, @@ -95,4 +99,15 @@ public void clear(RuleSet ruleSet) { public Feature get(RuleSet ruleSet) { return rulesetToFeature.get(ruleSet); } + + /** + * Returns the used {@link Feature} for the given {@link RuleSet} and removes it. + * + * @param ruleSet The {@link RuleSet} to get its {@link Feature}. + * @return The {@link Feature} used for the given {@link RuleSet} or {@code null} if not + * available. + */ + public Feature remove(RuleSet ruleSet) { + return rulesetToFeature.remove(ruleSet); + } } From b3884966d1b7fd14e8fd1ed5823a3da70e2d430f Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 13 Aug 2025 09:43:23 +0200 Subject: [PATCH 31/62] Spotless --- .../strategy/JavaCardDLStrategyFactory.java | 4 -- .../key/strategy/ModularJavaDLStrategy.java | 16 +++--- .../uka/ilkd/key/strategy/SymExStrategy.java | 56 ++++++++++--------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index b490c68691..691d491ee1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java @@ -3,10 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import java.util.LinkedList; -import java.util.List; -import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.strategy.definition.AbstractStrategyPropertyDefinition; import de.uka.ilkd.key.strategy.definition.OneOfStrategyPropertyDefinition; @@ -16,7 +13,6 @@ import org.key_project.logic.Name; -import org.jspecify.annotations.NonNull; /** * diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index a565317a46..56479c42bc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -83,14 +83,14 @@ private RuleSetDispatchFeature resolveConflicts() { private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, List value) { switch (rs.name().toString()) { - case "order_terms" -> { - var intStrat = value.getFirst(); - var javaDLStrat = value.get(1); - bindRuleSet(d, "order_terms", - ifZero(applyTF("commEqLeft", tf.intF), - intStrat.getCostDispatcher().remove(rs), - javaDLStrat.getCostDispatcher().remove(rs))); - } + case "order_terms" -> { + var intStrat = value.getFirst(); + var javaDLStrat = value.get(1); + bindRuleSet(d, "order_terms", + ifZero(applyTF("commEqLeft", tf.intF), + intStrat.getCostDispatcher().remove(rs), + javaDLStrat.getCostDispatcher().remove(rs))); + } } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index 556cde7377..778b44b545 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -61,13 +61,14 @@ private Feature setupGlobalF(Feature dispatcher) { final String methProp = strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); switch (methProp) { - case StrategyProperties.METHOD_CONTRACT -> methodSpecF = methodSpecFeature(longConst(-20)); - case StrategyProperties.METHOD_EXPAND, StrategyProperties.METHOD_NONE -> methodSpecF = - methodSpecFeature(inftyConst()); - default -> { - methodSpecF = null; - assert false; - } + case StrategyProperties.METHOD_CONTRACT -> + methodSpecF = methodSpecFeature(longConst(-20)); + case StrategyProperties.METHOD_EXPAND, StrategyProperties.METHOD_NONE -> methodSpecF = + methodSpecFeature(inftyConst()); + default -> { + methodSpecF = null; + assert false; + } } Feature loopInvF; @@ -159,29 +160,32 @@ private RuleSetDispatchFeature setupCostComputationF() { final String methProp = strategyProperties.getProperty(StrategyProperties.METHOD_OPTIONS_KEY); switch (methProp) { - case StrategyProperties.METHOD_CONTRACT -> - /* - * If method treatment by contracts is chosen, this does not mean that method expansion - * is disabled. The original cost was 200 and is now increased to 2000 in order to - * repress method expansion stronger when method treatment by contracts is chosen. - */ - bindRuleSet(d, "method_expand", longConst(2000)); - case StrategyProperties.METHOD_EXPAND -> bindRuleSet(d, "method_expand", longConst(100)); - case StrategyProperties.METHOD_NONE -> bindRuleSet(d, "method_expand", inftyConst()); - default -> throw new RuntimeException("Unexpected strategy property " + methProp); + case StrategyProperties.METHOD_CONTRACT -> + /* + * If method treatment by contracts is chosen, this does not mean that method + * expansion + * is disabled. The original cost was 200 and is now increased to 2000 in order to + * repress method expansion stronger when method treatment by contracts is chosen. + */ + bindRuleSet(d, "method_expand", longConst(2000)); + case StrategyProperties.METHOD_EXPAND -> + bindRuleSet(d, "method_expand", longConst(100)); + case StrategyProperties.METHOD_NONE -> bindRuleSet(d, "method_expand", inftyConst()); + default -> throw new RuntimeException("Unexpected strategy property " + methProp); } final String mpsProp = strategyProperties.getProperty(StrategyProperties.MPS_OPTIONS_KEY); switch (mpsProp) { - case StrategyProperties.MPS_MERGE -> - /* - * For this case, we use a special feature, since deleting merge points should only be - * done after a merge rule application. - */ - bindRuleSet(d, "merge_point", DeleteMergePointRuleFeature.INSTANCE); - case StrategyProperties.MPS_SKIP -> bindRuleSet(d, "merge_point", longConst(-5000)); - case StrategyProperties.MPS_NONE -> bindRuleSet(d, "merge_point", inftyConst()); - default -> throw new RuntimeException("Unexpected strategy property " + mpsProp); + case StrategyProperties.MPS_MERGE -> + /* + * For this case, we use a special feature, since deleting merge points should only + * be + * done after a merge rule application. + */ + bindRuleSet(d, "merge_point", DeleteMergePointRuleFeature.INSTANCE); + case StrategyProperties.MPS_SKIP -> bindRuleSet(d, "merge_point", longConst(-5000)); + case StrategyProperties.MPS_NONE -> bindRuleSet(d, "merge_point", inftyConst()); + default -> throw new RuntimeException("Unexpected strategy property " + mpsProp); } bindRuleSet(d, "modal_tautology", longConst(-10000)); From 7e37d27b6eae52103ccb9748daa8cab4008ce11e Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 13 Aug 2025 10:12:39 +0200 Subject: [PATCH 32/62] Add conflict resolution for int --- .../ilkd/key/strategy/IntegerStrategy.java | 33 +++++++++++++++ .../ilkd/key/strategy/JavaCardDLStrategy.java | 42 ++++--------------- .../key/strategy/ModularJavaDLStrategy.java | 26 ++++++++++++ .../rules/integerSimplificationRules.key | 4 +- .../key/proof/rules/ruleSetsDeclarations.key | 1 - 5 files changed, 68 insertions(+), 38 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 2aa10da06b..e69c674c06 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -27,6 +27,7 @@ import org.key_project.prover.strategy.costbased.TopRuleAppCost; import org.key_project.prover.strategy.costbased.feature.Feature; import org.key_project.prover.strategy.costbased.feature.FocusInAntecFeature; +import org.key_project.prover.strategy.costbased.feature.ScaleFeature; import org.key_project.prover.strategy.costbased.feature.SumFeature; import org.key_project.prover.strategy.costbased.termfeature.TermFeature; import org.key_project.prover.strategy.costbased.termgenerator.SequentFormulasGenerator; @@ -151,6 +152,38 @@ private RuleSetDispatchFeature setupCostComputationF() { add(applyTF("commEqRight", tf.monomial), applyTF("commEqLeft", tf.polynomial), monSmallerThan("commEqLeft", "commEqRight", numbers), longConst(-5000))); + final TermBuffer equation = new TermBuffer(); + final TermBuffer left = new TermBuffer(); + final TermBuffer right = new TermBuffer(); + bindRuleSet(d, "apply_equations", + SumFeature.createSum( + add(applyTF(FocusProjection.create(0), tf.monomial), + ScaleFeature.createScaled(FindRightishFeature.create(numbers), 5.0)), + ifZero(MatchedAssumesFeature.INSTANCE, + add(CheckApplyEqFeature.INSTANCE, let(equation, AssumptionProjection.create(0), + add(not(applyTF(equation, ff.update)), + // there might be updates in + // front of the assumption + // formula; in this case we wait + // until the updates have + // been applied + let(left, sub(equation, 0), + let(right, sub(equation, 1), + add(applyTF(left, tf.nonNegOrNonCoeffMonomial), + applyTF(right, tf.polynomial), + MonomialsSmallerThanFeature.create(right, left, + numbers)))))))), + longConst(-4000))); + + final TermBuffer l = new TermBuffer(); + final TermBuffer r = new TermBuffer(); + bindRuleSet(d, "apply_equations_andOr", + add(let(l, instOf("applyEqLeft"), + let(r, instOf("applyEqRight"), + add(applyTF(l, tf.nonNegOrNonCoeffMonomial), applyTF(r, tf.polynomial), + MonomialsSmallerThanFeature.create(r, l, numbers)))), + longConst(-150))); + // For taclets that need instantiation, but where the instantiation is // deterministic and does not have to be repeated at a later point, we // setup the same feature terms as in the instantiation method. The diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 18ed412b90..e211cae85c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -227,7 +227,7 @@ private RuleSetDispatchFeature setupCostComputationF() { setupReplaceKnown(d); - setupApplyEq(d, numbers); + setupApplyEq(d); bindRuleSet(d, "insert_eq_nonrigid", applyTF(FocusProjection.create(0), IsNonRigidTermFeature.INSTANCE)); @@ -607,7 +607,7 @@ private void setupSplittingApproval(RuleSetDispatchFeature d) { // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// - private void setupApplyEq(RuleSetDispatchFeature d, IntegerLDT numbers) { + private void setupApplyEq(RuleSetDispatchFeature d) { final TermBuffer equation = new TermBuffer(); final TermBuffer left = new TermBuffer(); final TermBuffer right = new TermBuffer(); @@ -617,9 +617,7 @@ private void setupApplyEq(RuleSetDispatchFeature d, IntegerLDT numbers) { // this is important for reducing polynomials (start with the biggest // summands) bindRuleSet(d, "apply_equations", - SumFeature.createSum(ifZero(applyTF(FocusProjection.create(0), tf.intF), - add(applyTF(FocusProjection.create(0), tf.monomial), - ScaleFeature.createScaled(FindRightishFeature.create(numbers), 5.0))), + SumFeature.createSum( ifZero(MatchedAssumesFeature.INSTANCE, add(CheckApplyEqFeature.INSTANCE, let(equation, AssumptionProjection.create(0), add(not(applyTF(equation, ff.update)), @@ -629,32 +627,8 @@ private void setupApplyEq(RuleSetDispatchFeature d, IntegerLDT numbers) { // until the updates have // been applied let(left, sub(equation, 0), - let(right, sub(equation, 1), ifZero(applyTF(left, tf.intF), - add(applyTF(left, tf.nonNegOrNonCoeffMonomial), - applyTF(right, tf.polynomial), - MonomialsSmallerThanFeature.create(right, left, numbers)), - TermSmallerThanFeature.create(right, left)))))))), - longConst(-4000))); - - bindRuleSet(d, "int_apply_equations", - SumFeature.createSum(ifZero(applyTF(FocusProjection.create(0), tf.intF), - add(applyTF(FocusProjection.create(0), tf.monomial), - ScaleFeature.createScaled(FindRightishFeature.create(numbers), 5.0)), - inftyConst()), - ifZero(MatchedAssumesFeature.INSTANCE, - add(CheckApplyEqFeature.INSTANCE, let(equation, AssumptionProjection.create(0), - add(not(applyTF(equation, ff.update)), - // there might be updates in - // front of the assumption - // formula; in this case we wait - // until the updates have - // been applied - let(left, sub(equation, 0), - let(right, sub(equation, 1), ifZero(applyTF(left, tf.intF), - add(applyTF(left, tf.nonNegOrNonCoeffMonomial), - applyTF(right, tf.polynomial), - MonomialsSmallerThanFeature.create(right, left, numbers)), - inftyConst()))))))), + let(right, sub(equation, 1), + TermSmallerThanFeature.create(right, left))))))), longConst(-4000))); } @@ -700,10 +674,8 @@ private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numb final TermBuffer right = new TermBuffer(); bindRuleSet(d, "apply_equations_andOr", add(let(left, instOf("applyEqLeft"), - let(right, instOf("applyEqRight"), ifZero(applyTF(left, tf.intF), - add(applyTF(left, tf.nonNegOrNonCoeffMonomial), applyTF(right, tf.polynomial), - MonomialsSmallerThanFeature.create(right, left, numbers)), - TermSmallerThanFeature.create(right, left)))), + let(right, instOf("applyEqRight"), + TermSmallerThanFeature.create(right, left))), longConst(-150))); bindRuleSet(d, "distrQuantifier", diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 56479c42bc..9b7c27db5e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -15,6 +15,7 @@ import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; import de.uka.ilkd.key.strategy.feature.NonDuplicateAppFeature; import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; +import de.uka.ilkd.key.strategy.termProjection.FocusProjection; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -91,6 +92,26 @@ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, intStrat.getCostDispatcher().remove(rs), javaDLStrat.getCostDispatcher().remove(rs))); } + case "apply_equations" -> { + var intStrat = value.getFirst(); + var javaDLStrat = value.get(1); + bindRuleSet(d, "apply_equations", + ifZero(applyTF(FocusProjection.create(0), tf.intF), + intStrat.getCostDispatcher().remove(rs), + javaDLStrat.getCostDispatcher().remove(rs))); + } + case "apply_equations_andOr" -> { + var intStrat = value.getFirst(); + var javaDLStrat = value.get(1); + if (quantifierInstantiatedEnabled()) { + bindRuleSet(d, "apply_equations_andOr", + ifZero(applyTF(FocusProjection.create(0), tf.intF), + intStrat.getCostDispatcher().remove(rs), + javaDLStrat.getCostDispatcher().remove(rs))); + } else { + bindRuleSet(d, "apply_equations_andOr", inftyConst()); + } + } } } @@ -186,4 +207,9 @@ private class ReduceTillMaxFeature implements Feature { RuleAppCost::add, s -> mapper.compute(s, app, pos, (Goal) goal, mState)); } } + + private boolean quantifierInstantiatedEnabled() { + return !StrategyProperties.QUANTIFIERS_NONE + .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); + } } diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key index cea28c7ca0..ca36ae7762 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key @@ -1785,7 +1785,7 @@ \replacewith(#divideMonomials(applyEqDividend, applyEqDivisor) * (i0 + applyEqDivisor * -1) + applyEqDividend) - \heuristics(polySimp_applyEq, int_apply_equations, notHumanReadable) + \heuristics(polySimp_applyEq, apply_equations, notHumanReadable) }; apply_eq_monomials_rigid { @@ -1794,7 +1794,7 @@ \replacewith(#divideMonomials(applyEqDividend, applyEqDivisorr) * (i0r + applyEqDivisorr * -1) + applyEqDividend) - \heuristics(polySimp_applyEqRigid, int_apply_equations, notHumanReadable) + \heuristics(polySimp_applyEqRigid, apply_equations, notHumanReadable) }; apply_eq_pseudo_eq { diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key index e4734b8edc..1be9befdfb 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key @@ -85,7 +85,6 @@ test_gen_quan_num; order_terms; apply_equations; - int_apply_equations; insert_eq_nonrigid; simplify_literals; eval_literals; From ccf8c0e060cfe8fe2a151b59e15bece79550b4d3 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 13 Aug 2025 11:03:15 +0200 Subject: [PATCH 33/62] Add FOL Strat --- .../de/uka/ilkd/key/strategy/FOLStrategy.java | 627 ++++++++++++++++++ .../ilkd/key/strategy/FOLStrategyFactory.java | 65 ++ .../ilkd/key/strategy/IntegerStrategy.java | 1 + .../ilkd/key/strategy/JavaCardDLStrategy.java | 503 +------------- .../strategy/JavaCardDLStrategyFactory.java | 36 +- .../key/strategy/ModularJavaDLStrategy.java | 21 +- .../ModularJavaDLStrategyFactory.java | 2 +- .../performance/DataRecordingStrategy.java | 13 +- 8 files changed, 719 insertions(+), 549 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java new file mode 100644 index 0000000000..e4656866b9 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -0,0 +1,627 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.ldt.IntegerLDT; +import de.uka.ilkd.key.ldt.LocSetLDT; +import de.uka.ilkd.key.logic.op.Equality; +import de.uka.ilkd.key.logic.op.Junctor; +import de.uka.ilkd.key.logic.op.Quantifier; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.feature.*; +import de.uka.ilkd.key.strategy.quantifierHeuristics.*; +import de.uka.ilkd.key.strategy.termProjection.AssumptionProjection; +import de.uka.ilkd.key.strategy.termProjection.FocusFormulaProjection; +import de.uka.ilkd.key.strategy.termProjection.FocusProjection; +import de.uka.ilkd.key.strategy.termProjection.TermBuffer; +import de.uka.ilkd.key.strategy.termfeature.ContainsExecutableCodeTermFeature; +import de.uka.ilkd.key.strategy.termgenerator.AllowedCutPositionsGenerator; +import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; +import de.uka.ilkd.key.strategy.termgenerator.TriggeredInstantiations; + +import org.key_project.logic.Name; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.rules.RuleSet; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.TopRuleAppCost; +import org.key_project.prover.strategy.costbased.feature.*; +import org.key_project.prover.strategy.costbased.feature.instantiator.ChoicePoint; +import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; +import org.key_project.prover.strategy.costbased.termfeature.IsNonRigidTermFeature; +import org.key_project.prover.strategy.costbased.termfeature.OperatorClassTF; + +import org.jspecify.annotations.NonNull; + +public class FOLStrategy extends AbstractFeatureStrategy { + public static final Name NAME = new Name("FOL Strategy"); + + protected final StrategyProperties strategyProperties; + + private final RuleSetDispatchFeature costComputationDispatcher; + private final RuleSetDispatchFeature approvalDispatcher; + private final RuleSetDispatchFeature instantiationDispatcher; + private final Feature costComputationF; + private final Feature approvalF; + private final Feature instantiationF; + + private final ArithTermFeatures tf; + private final FormulaTermFeatures ff; + private final ValueTermFeature vf; + + public FOLStrategy(Proof proof, StrategyProperties strategyProperties) { + super(proof); + + this.strategyProperties = (StrategyProperties) strategyProperties.clone(); + + this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); + this.ff = new FormulaTermFeatures(this.tf); + var heapLDT = getServices().getTypeConverter().getHeapLDT(); + vf = new ValueTermFeature(op(heapLDT.getNull())); + + costComputationDispatcher = setupCostComputationF(); + approvalDispatcher = setupApprovalDispatcher(); + instantiationDispatcher = setupInstantiationF(); + + costComputationF = costComputationDispatcher; + instantiationF = instantiationDispatcher; + approvalF = approvalDispatcher; + } + + private RuleSetDispatchFeature setupCostComputationF() { + final LocSetLDT locSetLDT = getServices().getTypeConverter().getLocSetLDT(); + final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + + bindRuleSet(d, "closure", -15000); + bindRuleSet(d, "alpha", -7000); + bindRuleSet(d, "delta", -6000); + bindRuleSet(d, "simplify_boolean", -200); + + final Feature findDepthFeature = + FindDepthFeature.getInstance(); + + bindRuleSet(d, "concrete", + add(longConst(-11000), + ScaleFeature.createScaled(findDepthFeature, 10.0))); + bindRuleSet(d, "simplify", -4500); + bindRuleSet(d, "simplify_enlarging", -2000); + bindRuleSet(d, "simplify_ENLARGING", -1900); + + // always give infinite cost to obsolete rules + bindRuleSet(d, "obsolete", inftyConst()); + + bindRuleSet(d, "no_self_application", + ifZero(MatchedAssumesFeature.INSTANCE, NoSelfApplicationFeature.INSTANCE)); + + bindRuleSet(d, "find_term_not_in_assumes", ifZero(MatchedAssumesFeature.INSTANCE, + not(contains(AssumptionProjection.create(0), FocusProjection.INSTANCE)))); + + bindRuleSet(d, "update_elim", + add(longConst(-8000), ScaleFeature.createScaled(findDepthFeature, 10.0))); + bindRuleSet(d, "update_apply_on_update", + add(longConst(-7000), ScaleFeature.createScaled(findDepthFeature, 10.0))); + bindRuleSet(d, "update_join", -4600); + bindRuleSet(d, "update_apply", -4500); + + setupSplitting(d); + + bindRuleSet(d, "gamma", add(not(isInstantiated("t")), + ifZero(allowQuantifierSplitting(), longConst(0), longConst(50)))); + bindRuleSet(d, "gamma_destructive", inftyConst()); + + bindRuleSet(d, "triggered", add(not(isTriggerVariableInstantiated()), longConst(500))); + + bindRuleSet(d, "comprehension_split", + add(applyTF(FocusFormulaProjection.INSTANCE, ff.notContainsExecutable), + ifZero(allowQuantifierSplitting(), longConst(2500), longConst(5000)))); + + setupReplaceKnown(d); + + setupEquationReasoning(d); + + bindRuleSet(d, "order_terms", + add(termSmallerThan("commEqLeft", "commEqRight"), longConst(-5000))); + + bindRuleSet(d, "simplify_instanceof_static", + add(EqNonDuplicateAppFeature.INSTANCE, longConst(-500))); + + bindRuleSet(d, "evaluate_instanceof", longConst(-500)); + + bindRuleSet(d, "instanceof_to_exists", TopLevelFindFeature.ANTEC); + + bindRuleSet(d, "try_apply_subst", + add(EqNonDuplicateAppFeature.INSTANCE, longConst(-10000))); + + // delete cast + bindRuleSet(d, "cast_deletion", + ifZero(implicitCastNecessary(instOf("castedTerm")), longConst(-5000), inftyConst())); + + bindRuleSet(d, "type_hierarchy_def", -6500); + + bindRuleSet(d, "cut", not(isInstantiated("cutFormula"))); + + if (quantifierInstantiatedEnabled()) { + setupFormulaNormalisation(d, numbers, locSetLDT); + } else { + bindRuleSet(d, "negationNormalForm", inftyConst()); + bindRuleSet(d, "moveQuantToLeft", inftyConst()); + bindRuleSet(d, "conjNormalForm", inftyConst()); + bindRuleSet(d, "apply_equations_andOr", inftyConst()); + bindRuleSet(d, "elimQuantifier", inftyConst()); + bindRuleSet(d, "distrQuantifier", inftyConst()); + bindRuleSet(d, "swapQuantifiers", inftyConst()); + bindRuleSet(d, "pullOutQuantifierAll", inftyConst()); + bindRuleSet(d, "pullOutQuantifierEx", inftyConst()); + } + + return d; + } + + private RuleSetDispatchFeature setupApprovalDispatcher() { + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + + setupQuantifierInstantiationApproval(d); + setupSplittingApproval(d); + + // Without EqNonDuplicateAppFeature.INSTANCE + // rule 'applyEq' might be applied on the same term + // without changing the sequent for a really long time. This is tested by + // TestSymbolicExecutionTreeBuilder#testInstanceOfNotInEndlessLoop() + bindRuleSet(d, "apply_equations", EqNonDuplicateAppFeature.INSTANCE); + + return d; + } + + private RuleSetDispatchFeature setupInstantiationF() { + enableInstantiate(); + + final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); + setupQuantifierInstantiation(d); + + disableInstantiate(); + return d; + } + + @Override + protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return instantiationF.computeCost(app, pio, goal, mState); + } + + @Override + protected RuleSetDispatchFeature getCostDispatcher() { + return costComputationDispatcher; + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return false; + } + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return approvalF.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; + } + + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null + || approvalDispatcher.get(rs) != null; + } + + @Override + public Name name() { + return NAME; + } + + /** + * Evaluate the cost of a RuleApp. + * + * @param app rule application + * @param pio corresponding {@link PosInOccurrence} + * @param goal corresponding goal + * @param mState the {@link MutableState} to query for information like current value of + * {@link TermBuffer}s or + * {@link ChoicePoint}s + * @return the cost of the rule application expressed as a RuleAppCost object. + * TopRuleAppCost.INSTANCE indicates that the rule shall not be applied at + * all (it is discarded by the strategy). + */ + @Override + public > RuleAppCost computeCost(@NonNull RuleApp app, + @NonNull PosInOccurrence pio, + @NonNull GOAL goal, + @NonNull MutableState mState) { + return costComputationF.computeCost(app, pio, goal, mState); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Normalisation of formulas; this is mostly a pre-processing step for + // handling quantified formulas + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numbers, + LocSetLDT locSetLDT) { + + bindRuleSet(d, "negationNormalForm", add(BelowBinderFeature.getInstance(), + longConst(-500), + ScaleFeature.createScaled(FindDepthFeature.getInstance(), 10.0))); + + bindRuleSet(d, "moveQuantToLeft", + add(quantifiersMightSplit() ? longConst(0) + : applyTF(FocusFormulaProjection.INSTANCE, ff.quantifiedPureLitConjDisj), + longConst(-550))); + + bindRuleSet(d, "conjNormalForm", + ifZero( + add(or(FocusInAntecFeature.getInstance(), notBelowQuantifier()), + NotInScopeOfModalityFeature.INSTANCE), + add(longConst(-150), + ScaleFeature.createScaled(FindDepthFeature.getInstance(), 20)), + inftyConst())); + + bindRuleSet(d, "setEqualityBlastingRight", longConst(-100)); + + bindRuleSet(d, "cnf_setComm", + add(SetsSmallerThanFeature.create(instOf("commRight"), instOf("commLeft"), locSetLDT), + NotInScopeOfModalityFeature.INSTANCE, longConst(-800))); + + bindRuleSet(d, "elimQuantifier", -1000); + bindRuleSet(d, "elimQuantifierWithCast", 50); + + final TermBuffer left = new TermBuffer(); + final TermBuffer right = new TermBuffer(); + bindRuleSet(d, "apply_equations_andOr", + add(let(left, instOf("applyEqLeft"), + let(right, instOf("applyEqRight"), + TermSmallerThanFeature.create(right, left))), + longConst(-150))); + + bindRuleSet(d, "distrQuantifier", + add(or( + applyTF(FocusProjection.INSTANCE, + add(ff.quantifiedClauseSet, not(opSub(Quantifier.ALL, ff.orF)), + EliminableQuantifierTF.INSTANCE)), + SumFeature.createSum(onlyInScopeOfQuantifiers(), + SplittableQuantifiedFormulaFeature.INSTANCE, + ifZero(FocusInAntecFeature.getInstance(), + applyTF(FocusProjection.INSTANCE, sub(ff.andF)), + applyTF(FocusProjection.INSTANCE, sub(ff.orF))))), + longConst(-300))); + + bindRuleSet(d, "swapQuantifiers", + add(applyTF(FocusProjection.INSTANCE, add(ff.quantifiedClauseSet, + EliminableQuantifierTF.INSTANCE, sub(not(EliminableQuantifierTF.INSTANCE)))), + longConst(-300))); + + // category "conjunctive normal form" + + bindRuleSet(d, "cnf_orComm", + SumFeature.createSum(applyTF("commRight", ff.clause), + applyTFNonStrict("commResidue", ff.clauseSet), + or(applyTF("commLeft", ff.andF), + add(applyTF("commLeft", ff.literal), + literalsSmallerThan("commRight", "commLeft", numbers))), + longConst(-100))); + + bindRuleSet(d, "cnf_orAssoc", + SumFeature.createSum(applyTF("assoc0", ff.clause), + applyTF("assoc1", ff.clause), applyTF("assoc2", ff.literal), longConst(-80))); + + bindRuleSet(d, "cnf_andComm", + SumFeature.createSum(applyTF("commLeft", ff.clause), + applyTF("commRight", ff.clauseSet), applyTFNonStrict("commResidue", ff.clauseSet), + // at least one of the subformulas has to be a literal; + // otherwise, sorting is not likely to have any big effect + ifZero( + add(applyTF("commLeft", not(ff.literal)), + applyTF("commRight", rec(ff.andF, not(ff.literal)))), + longConst(100), longConst(-60)), + clausesSmallerThan("commRight", "commLeft", numbers))); + + bindRuleSet(d, "cnf_andAssoc", + SumFeature.createSum(applyTF("assoc0", ff.clauseSet), + applyTF("assoc1", ff.clauseSet), applyTF("assoc2", ff.clause), longConst(-10))); + + bindRuleSet(d, "cnf_dist", + SumFeature.createSum(applyTF("distRight0", ff.clauseSet), + applyTF("distRight1", ff.clauseSet), ifZero(applyTF("distLeft", ff.clause), + longConst(-15), applyTF("distLeft", ff.clauseSet)), + longConst(-35))); + + final TermBuffer superFor = new TermBuffer(); + final Feature onlyBelowQuanAndOr = + sum(superFor, SuperTermGenerator.upwards(any(), getServices()), + applyTF(superFor, or(ff.quantifiedFor, ff.andF, ff.orF))); + + final Feature belowUnskolemisableQuantifier = + ifZero(FocusInAntecFeature.getInstance(), + not(sum(superFor, SuperTermGenerator.upwards(any(), getServices()), + not(applyTF(superFor, op(Quantifier.ALL))))), + not(sum(superFor, SuperTermGenerator.upwards(any(), getServices()), + not(applyTF(superFor, op(Quantifier.EX)))))); + + bindRuleSet(d, "cnf_expandIfThenElse", add( + isBelow(OperatorClassTF.create(Quantifier.class)), + onlyBelowQuanAndOr, belowUnskolemisableQuantifier)); + + final Feature pullOutQuantifierAllowed = + add(isBelow(OperatorClassTF.create(Quantifier.class)), onlyBelowQuanAndOr, applyTF( + FocusProjection.create(0), sub(ff.quantifiedClauseSet, ff.quantifiedClauseSet))); + + bindRuleSet(d, "pullOutQuantifierUnifying", -20); + + bindRuleSet(d, "pullOutQuantifierAll", add(pullOutQuantifierAllowed, + ifZero(FocusInAntecFeature.getInstance(), longConst(-20), longConst(-40)))); + + bindRuleSet(d, "pullOutQuantifierEx", add(pullOutQuantifierAllowed, + ifZero(FocusInAntecFeature.getInstance(), longConst(-40), longConst(-20)))); + } + + private Feature clausesSmallerThan(String smaller, String bigger, IntegerLDT numbers) { + return ClausesSmallerThanFeature.create(instOf(smaller), instOf(bigger), numbers); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Heuristic instantiation of quantified formulas + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private void setupQuantifierInstantiation(RuleSetDispatchFeature d) { + if (quantifierInstantiatedEnabled()) { + final TermBuffer varInst = new TermBuffer(); + final Feature branchPrediction = InstantiationCostScalerFeature + .create(InstantiationCost.create(varInst), allowQuantifierSplitting()); + + bindRuleSet(d, "gamma", + SumFeature.createSum(FocusInAntecFeature.getInstance(), + applyTF(FocusProjection.create(0), + add(ff.quantifiedClauseSet, + instQuantifiersWithQueries() ? longTermConst(0) + : ff.notContainsExecutable)), + forEach(varInst, HeuristicInstantiation.INSTANCE, + add(instantiate("t", varInst), branchPrediction, longConst(10))))); + final TermBuffer splitInst = new TermBuffer(); + + bindRuleSet(d, "triggered", + SumFeature.createSum(forEach(splitInst, TriggeredInstantiations.create(true), + add(instantiateTriggeredVariable(splitInst), longConst(500))), + longConst(1500))); + + } else { + bindRuleSet(d, "gamma", inftyConst()); + bindRuleSet(d, "triggered", inftyConst()); + } + } + + private void setupQuantifierInstantiationApproval(RuleSetDispatchFeature d) { + if (quantifierInstantiatedEnabled()) { + final TermBuffer varInst = new TermBuffer(); + + bindRuleSet(d, "gamma", add(isInstantiated("t"), + not(sum(varInst, HeuristicInstantiation.INSTANCE, not(eq(instOf("t"), varInst)))), + InstantiationCostScalerFeature.create(InstantiationCost.create(instOf("t")), + longConst(0)))); + + final TermBuffer splitInst = new TermBuffer(); + bindRuleSet(d, "triggered", + add(isTriggerVariableInstantiated(), + not(sum(splitInst, TriggeredInstantiations.create(false), + not(eq(instOfTriggerVariable(), splitInst)))))); + } else { + bindRuleSet(d, "gamma", inftyConst()); + bindRuleSet(d, "triggered", inftyConst()); + } + } + + + protected final Feature onlyInScopeOfQuantifiers() { + final TermBuffer buf = new TermBuffer(); + return sum(buf, SuperTermGenerator.upwards(any(), getServices()), + applyTF(buf, ff.quantifiedFor)); + } + + protected Feature notBelowQuantifier() { + final TermBuffer superFor = new TermBuffer(); + return or(TopLevelFindFeature.ANTEC_OR_SUCC, + sum(superFor, SuperTermGenerator.upwards(any(), getServices()), + not(applyTF(superFor, OperatorClassTF.create(Quantifier.class))))); + } + + private void setupReplaceKnown(RuleSetDispatchFeature d) { + final Feature commonF = + add(ifZero(MatchedAssumesFeature.INSTANCE, DiffFindAndIfFeature.INSTANCE), + longConst(-5000), + add(DiffFindAndReplacewithFeature.INSTANCE, + ScaleFeature.createScaled(CountMaxDPathFeature.INSTANCE, 10.0))); + + bindRuleSet(d, "replace_known_left", commonF); + + bindRuleSet(d, "replace_known_right", + add(commonF, ifZero(directlyBelowSymbolAtIndex(Junctor.IMP, 1), longConst(100), + ifZero(directlyBelowSymbolAtIndex(Equality.EQV, -1), longConst(100))))); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Application of beta- and cut-rules to handle disjunctions + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private void setupSplitting(RuleSetDispatchFeature d) { + final TermBuffer subFor = new TermBuffer(); + final Feature noCutsAllowed = + sum(subFor, AllowedCutPositionsGenerator.INSTANCE, not(applyTF(subFor, ff.cutAllowed))); + bindRuleSet(d, "beta", + SumFeature.createSum(noCutsAllowed, + ifZero(PurePosDPathFeature.INSTANCE, longConst(-200)), + ScaleFeature.createScaled(CountPosDPathFeature.INSTANCE, -3.0), + ScaleFeature.createScaled(CountMaxDPathFeature.INSTANCE, 10.0), longConst(20))); + TermBuffer superF = new TermBuffer(); + final ProjectionToTerm splitCondition = sub(FocusProjection.INSTANCE, 0); + bindRuleSet(d, "split_cond", add(// do not split over formulas containing auxiliary + // variables + applyTF(FocusProjection.INSTANCE, + rec(any(), not(selectSkolemConstantTermFeature()))), + // prefer splits when condition has quantifiers (less + // likely to be simplified away) + applyTF(splitCondition, + rec(ff.quantifiedFor, ifZero(ff.quantifiedFor, longTermConst(-10)))), + FindDepthFeature.getInstance(), // prefer top level splits + ScaleFeature.createAffine(countOccurrences(splitCondition), -10, 10), + sum(superF, SuperTermGenerator.upwards(any(), getServices()), + applyTF(superF, not(ff.elemUpdate))), + ifZero(applyTF(FocusProjection.INSTANCE, ContainsExecutableCodeTermFeature.PROGRAMS), + longConst(-100), longConst(25)))); + ProjectionToTerm cutFormula = instOf("cutFormula"); + Feature countOccurrencesInSeq = + ScaleFeature.createAffine(countOccurrences(cutFormula), -10, 10); + bindRuleSet(d, "cut_direct", + SumFeature + .createSum( + not(TopLevelFindFeature.ANTEC_OR_SUCC_WITH_UPDATE), + AllowedCutPositionFeature.INSTANCE, + ifZero(notBelowQuantifier(), + add( + applyTF(cutFormula, add(ff.cutAllowed, + // do not cut over formulas containing + // auxiliary variables + rec(any(), not(selectSkolemConstantTermFeature())))), + // prefer cuts over "something = null" + ifZero(applyTF(FocusProjection.INSTANCE, + opSub(tf.eq, any(), vf.nullTerm)), + longConst(-5), longConst(0)), + // punish cuts over formulas containing anon heap functions + ifZero(applyTF(cutFormula, rec(any(), not(anonHeapTermFeature()))), + longConst(0), longConst(1000)), + countOccurrencesInSeq, // standard costs + longConst(100)), + SumFeature // check for cuts below quantifiers + .createSum(applyTF(cutFormula, ff.cutAllowedBelowQuantifier), + applyTF(FocusFormulaProjection.INSTANCE, + ff.quantifiedClauseSet), + ifZero(allowQuantifierSplitting(), longConst(0), + longConst(100)))))); + } + + private void setupSplittingApproval(RuleSetDispatchFeature d) { + bindRuleSet(d, "beta", allowSplitting(FocusFormulaProjection.INSTANCE)); + + bindRuleSet(d, "split_cond", allowSplitting(FocusProjection.INSTANCE)); + + final TermBuffer subFor = new TermBuffer(); + final Feature compareCutAllowed = ifZero(applyTF(subFor, ff.cutAllowed), + leq(applyTF("cutFormula", ff.cutPriority), applyTF(subFor, ff.cutPriority))); + + final Feature noBetterCut = + sum(subFor, AllowedCutPositionsGenerator.INSTANCE, compareCutAllowed); + + bindRuleSet(d, "cut_direct", add(allowSplitting(FocusFormulaProjection.INSTANCE), + ifZero(notBelowQuantifier(), noBetterCut))); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Application of equations + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private void setupEquationReasoning(RuleSetDispatchFeature d) { + final TermBuffer equation = new TermBuffer(); + final TermBuffer left = new TermBuffer(); + final TermBuffer right = new TermBuffer(); + + // applying equations less deep/less leftish in terms/formulas is + // preferred + // this is important for reducing polynomials (start with the biggest + // summands) + bindRuleSet(d, "apply_equations", + SumFeature.createSum( + ifZero(MatchedAssumesFeature.INSTANCE, + add(CheckApplyEqFeature.INSTANCE, let(equation, AssumptionProjection.create(0), + add(not(applyTF(equation, ff.update)), + // there might be updates in + // front of the assumption + // formula; in this case we wait + // until the updates have + // been applied + let(left, sub(equation, 0), + let(right, sub(equation, 1), + TermSmallerThanFeature.create(right, left))))))), + longConst(-4000))); + + bindRuleSet(d, "insert_eq_nonrigid", + applyTF(FocusProjection.create(0), IsNonRigidTermFeature.INSTANCE)); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // Queries for the active taclet options + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + private boolean instQuantifiersWithQueries() { + return StrategyProperties.QUANTIFIERS_INSTANTIATE + .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); + } + + private boolean quantifiersMightSplit() { + return StrategyProperties.QUANTIFIERS_INSTANTIATE + .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)) + || StrategyProperties.QUANTIFIERS_NON_SPLITTING_WITH_PROGS.equals( + strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); + } + + private Feature allowQuantifierSplitting() { + if (StrategyProperties.QUANTIFIERS_INSTANTIATE.equals( + strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY))) { + return longConst(0); + } + if (StrategyProperties.QUANTIFIERS_NON_SPLITTING_WITH_PROGS.equals( + strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY))) { + return sequentContainsNoPrograms(); + } + return inftyConst(); + } + + private boolean quantifierInstantiatedEnabled() { + return !StrategyProperties.QUANTIFIERS_NONE + .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); + } + + private Feature allowSplitting(ProjectionToTerm focus) { + if (normalSplitting()) { + return longConst(0); + } + if (StrategyProperties.SPLITTING_DELAYED + .equals(strategyProperties.getProperty(StrategyProperties.SPLITTING_OPTIONS_KEY))) { + return or(applyTF(focus, ContainsExecutableCodeTermFeature.PROGRAMS), + sequentContainsNoPrograms()); + } + // else: SPLITTING_OFF + return applyTF(focus, ContainsExecutableCodeTermFeature.PROGRAMS); + } + + private boolean normalSplitting() { + return StrategyProperties.SPLITTING_NORMAL + .equals(strategyProperties.getProperty(StrategyProperties.SPLITTING_OPTIONS_KEY)); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java new file mode 100644 index 0000000000..85665c6fc5 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java @@ -0,0 +1,65 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.OneOfStrategyPropertyDefinition; +import de.uka.ilkd.key.strategy.definition.StrategyPropertyValueDefinition; +import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; + +import org.key_project.logic.Name; + +import org.jspecify.annotations.NonNull; + +public class FOLStrategyFactory implements StrategyFactory { + public static final String TOOL_TIP_QUANTIFIER_NONE = + "" + "Do not instantiate quantified formulas automatically" + ""; + public static final String TOOL_TIP_QUANTIFIER_NO_SPLITS = "" + + "Instantiate quantified formulas automatically
" + + "with terms that occur in a sequent, but only if
" + + "this does not cause proof splitting. Further, quantified
" + + "formulas that contain queries are not instantiated
" + "automatically." + ""; + public static final String TOOL_TIP_QUANTIFIER_NO_SPLITS_WITH_PROGS = + "" + "Instantiate quantified formulas automatically
" + + "with terms that occur in a sequent, but if the
" + + "sequent contains programs then only perform
" + + "instantiations that do not cause proof splitting.
" + + "Further, quantified formulas that contain queries
" + + "are not instantiated automatically." + ""; + public static final String TOOL_TIP_QUANTIFIER_FREE = + "" + "Instantiate quantified formulas automatically
" + + "with terms that occur in a sequent, also if this
" + + "might cause proof splitting." + ""; + + @Override + public Strategy<@NonNull Goal> create(Proof proof, StrategyProperties strategyProperties) { + return new FOLStrategy(proof, strategyProperties); + } + + private static OneOfStrategyPropertyDefinition getQuantifierTreatment() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.QUANTIFIERS_OPTIONS_KEY, + "Quantifier treatment", 2, + new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_NONE, "None", + TOOL_TIP_QUANTIFIER_NONE, 2, 4), + new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_NON_SPLITTING, + "No Splits", TOOL_TIP_QUANTIFIER_NO_SPLITS, 6, 2), + new StrategyPropertyValueDefinition( + StrategyProperties.QUANTIFIERS_NON_SPLITTING_WITH_PROGS, "No Splits with Progs", + TOOL_TIP_QUANTIFIER_NO_SPLITS_WITH_PROGS, 2, 4), + new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_INSTANTIATE, "Free", + TOOL_TIP_QUANTIFIER_FREE, 6, 2)); + } + + @Override + public StrategySettingsDefinition getSettingsDefinition() { + final OneOfStrategyPropertyDefinition quantifierTreatment = getQuantifierTreatment(); + return new StrategySettingsDefinition("FOL Options", quantifierTreatment); + } + + @Override + public Name name() { + return FOLStrategy.NAME; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index e69c674c06..352b9aa7f4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -141,6 +141,7 @@ private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); + bindRuleSet(d, "simplify_int", inftyConst()); setupArithPrimaryCategories(d); setupPolySimp(d, numbers); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index e211cae85c..8087f0a10e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -6,27 +6,13 @@ import java.util.concurrent.atomic.AtomicLong; import de.uka.ilkd.key.ldt.HeapLDT; -import de.uka.ilkd.key.ldt.IntegerLDT; -import de.uka.ilkd.key.ldt.LocSetLDT; -import de.uka.ilkd.key.logic.op.Equality; -import de.uka.ilkd.key.logic.op.Junctor; -import de.uka.ilkd.key.logic.op.Quantifier; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.UseDependencyContractRule; import de.uka.ilkd.key.strategy.feature.*; -import de.uka.ilkd.key.strategy.quantifierHeuristics.ClausesSmallerThanFeature; -import de.uka.ilkd.key.strategy.quantifierHeuristics.EliminableQuantifierTF; -import de.uka.ilkd.key.strategy.quantifierHeuristics.HeuristicInstantiation; -import de.uka.ilkd.key.strategy.quantifierHeuristics.InstantiationCost; -import de.uka.ilkd.key.strategy.quantifierHeuristics.InstantiationCostScalerFeature; -import de.uka.ilkd.key.strategy.quantifierHeuristics.SplittableQuantifiedFormulaFeature; import de.uka.ilkd.key.strategy.termProjection.*; import de.uka.ilkd.key.strategy.termfeature.*; -import de.uka.ilkd.key.strategy.termgenerator.AllowedCutPositionsGenerator; import de.uka.ilkd.key.strategy.termgenerator.HeapGenerator; -import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; -import de.uka.ilkd.key.strategy.termgenerator.TriggeredInstantiations; import de.uka.ilkd.key.util.MiscTools; import org.key_project.logic.Name; @@ -40,9 +26,6 @@ import org.key_project.prover.strategy.costbased.TopRuleAppCost; import org.key_project.prover.strategy.costbased.feature.*; import org.key_project.prover.strategy.costbased.feature.instantiator.ChoicePoint; -import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; -import org.key_project.prover.strategy.costbased.termfeature.IsNonRigidTermFeature; -import org.key_project.prover.strategy.costbased.termfeature.OperatorClassTF; import org.jspecify.annotations.NonNull; @@ -69,7 +52,6 @@ public class JavaCardDLStrategy extends AbstractFeatureStrategy { private final ArithTermFeatures tf; private final FormulaTermFeatures ff; - private final ValueTermFeature vf; protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) { @@ -80,7 +62,6 @@ protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); this.ff = new FormulaTermFeatures(this.tf); - this.vf = new ValueTermFeature(op(heapLDT.getNull())); costComputationDispatcher = setupCostComputationF(); approvalDispatcher = setupApprovalDispatcher(); @@ -105,7 +86,7 @@ public boolean isResponsibleFor(RuleSet rs) { || approvalDispatcher.get(rs) != null; } - protected Feature setupGlobalF(Feature dispatcher) { + protected Feature setupGlobalF(@NonNull Feature dispatcher) { final String queryProp = strategyProperties.getProperty(StrategyProperties.QUERY_OPTIONS_KEY); final Feature queryF; @@ -162,79 +143,22 @@ private Feature oneStepSimplificationFeature(Feature cost) { // ////////////////////////////////////////////////////////////////////////// private RuleSetDispatchFeature setupCostComputationF() { - final LocSetLDT locSetLDT = getServices().getTypeConverter().getLocSetLDT(); - final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); - final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); bindRuleSet(d, "semantics_blasting", inftyConst()); bindRuleSet(d, "simplify_heap_high_costs", inftyConst()); - bindRuleSet(d, "closure", -15000); - bindRuleSet(d, "alpha", -7000); - bindRuleSet(d, "delta", -6000); - bindRuleSet(d, "simplify_boolean", -200); - - final Feature findDepthFeature = - FindDepthFeature.getInstance(); - - bindRuleSet(d, "concrete", - add(longConst(-11000), - ScaleFeature.createScaled(findDepthFeature, 10.0))); - bindRuleSet(d, "simplify", -4500); - bindRuleSet(d, "simplify_enlarging", -2000); - bindRuleSet(d, "simplify_ENLARGING", -1900); - bindRuleSet(d, "simplify_int", inftyConst()); - bindRuleSet(d, "javaIntegerSemantics", ifZero(sequentContainsNoPrograms(), longConst(-5000), ifZero( leq(CountBranchFeature.INSTANCE, longConst(1)), longConst(-5000), inftyConst()))); - // always give infinite cost to obsolete rules - bindRuleSet(d, "obsolete", inftyConst()); - setupSelectSimplification(d); - bindRuleSet(d, "no_self_application", - ifZero(MatchedAssumesFeature.INSTANCE, NoSelfApplicationFeature.INSTANCE)); - - bindRuleSet(d, "find_term_not_in_assumes", ifZero(MatchedAssumesFeature.INSTANCE, - not(contains(AssumptionProjection.create(0), FocusProjection.INSTANCE)))); - - bindRuleSet(d, "update_elim", - add(longConst(-8000), ScaleFeature.createScaled(findDepthFeature, 10.0))); - bindRuleSet(d, "update_apply_on_update", - add(longConst(-7000), ScaleFeature.createScaled(findDepthFeature, 10.0))); - bindRuleSet(d, "update_join", -4600); - bindRuleSet(d, "update_apply", -4500); - - setupSplitting(d); - bindRuleSet(d, "test_gen", inftyConst()); bindRuleSet(d, "test_gen_empty_modality_hide", inftyConst()); bindRuleSet(d, "test_gen_quan", inftyConst()); bindRuleSet(d, "test_gen_quan_num", inftyConst()); - bindRuleSet(d, "gamma", add(not(isInstantiated("t")), - ifZero(allowQuantifierSplitting(), longConst(0), longConst(50)))); - bindRuleSet(d, "gamma_destructive", inftyConst()); - - bindRuleSet(d, "triggered", add(not(isTriggerVariableInstantiated()), longConst(500))); - - bindRuleSet(d, "comprehension_split", - add(applyTF(FocusFormulaProjection.INSTANCE, ff.notContainsExecutable), - ifZero(allowQuantifierSplitting(), longConst(2500), longConst(5000)))); - - setupReplaceKnown(d); - - setupApplyEq(d); - - bindRuleSet(d, "insert_eq_nonrigid", - applyTF(FocusProjection.create(0), IsNonRigidTermFeature.INSTANCE)); - - bindRuleSet(d, "order_terms", - add(termSmallerThan("commEqLeft", "commEqRight"), longConst(-5000))); - bindRuleSet(d, "simplify_literals", // ifZero ( ConstraintStrengthenFeatureUC.create(proof), // longConst ( 0 ), @@ -242,9 +166,7 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "nonDuplicateAppCheckEq", EqNonDuplicateAppFeature.INSTANCE); - bindRuleSet(d, "simplify_instanceof_static", - add(EqNonDuplicateAppFeature.INSTANCE, longConst(-500))); - + // TODO: rename rule set? bindRuleSet(d, "comprehensions", add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(-50))); @@ -254,13 +176,6 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "comprehensions_low_costs", add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(-5000))); - bindRuleSet(d, "evaluate_instanceof", longConst(-500)); - - bindRuleSet(d, "instanceof_to_exists", TopLevelFindFeature.ANTEC); - - bindRuleSet(d, "try_apply_subst", - add(EqNonDuplicateAppFeature.INSTANCE, longConst(-10000))); - // features influenced by the strategy options /* * boolean useBlockExpand = strategyProperties.getProperty( @@ -286,12 +201,6 @@ private RuleSetDispatchFeature setupCostComputationF() { * bindRuleSet ( d, "block_expand", useBlockExpand ? longConst ( 0 ) : inftyConst () ); */ - // delete cast - bindRuleSet(d, "cast_deletion", - ifZero(implicitCastNecessary(instOf("castedTerm")), longConst(-5000), inftyConst())); - - bindRuleSet(d, "type_hierarchy_def", -6500); - // partial inv axiom bindRuleSet(d, "partialInvAxiom", add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(10000))); @@ -304,26 +213,10 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "limitObserver", add(NonDuplicateAppModPositionFeature.INSTANCE, longConst(-200))); - bindRuleSet(d, "cut", not(isInstantiated("cutFormula"))); - setupUserTaclets(d); setupSystemInvariantSimp(d); - if (quantifierInstantiatedEnabled()) { - setupFormulaNormalisation(d, numbers, locSetLDT); - } else { - bindRuleSet(d, "negationNormalForm", inftyConst()); - bindRuleSet(d, "moveQuantToLeft", inftyConst()); - bindRuleSet(d, "conjNormalForm", inftyConst()); - bindRuleSet(d, "apply_equations_andOr", inftyConst()); - bindRuleSet(d, "elimQuantifier", inftyConst()); - bindRuleSet(d, "distrQuantifier", inftyConst()); - bindRuleSet(d, "swapQuantifiers", inftyConst()); - bindRuleSet(d, "pullOutQuantifierAll", inftyConst()); - bindRuleSet(d, "pullOutQuantifierEx", inftyConst()); - } - // chrisg: The following rule, if active, must be applied delta rules. if (autoInductionEnabled()) { bindRuleSet(d, "auto_induction", -6500); // chrisg @@ -401,20 +294,6 @@ private void setupSelectSimplification(final RuleSetDispatchFeature d) { add(isSelectSkolemConstantTerm("auxiliarySK"), longConst(-500))); } - private void setupReplaceKnown(RuleSetDispatchFeature d) { - final Feature commonF = - add(ifZero(MatchedAssumesFeature.INSTANCE, DiffFindAndIfFeature.INSTANCE), - longConst(-5000), - add(DiffFindAndReplacewithFeature.INSTANCE, - ScaleFeature.createScaled(CountMaxDPathFeature.INSTANCE, 10.0))); - - bindRuleSet(d, "replace_known_left", commonF); - - bindRuleSet(d, "replace_known_right", - add(commonF, ifZero(directlyBelowSymbolAtIndex(Junctor.IMP, 1), longConst(100), - ifZero(directlyBelowSymbolAtIndex(Equality.EQV, -1), longConst(100))))); - } - private void setupUserTaclets(RuleSetDispatchFeature d) { for (int i = 1; i <= StrategyProperties.USER_TACLETS_NUM; ++i) { final String userTacletsProbs = @@ -443,35 +322,6 @@ private void setupSystemInvariantSimp(RuleSetDispatchFeature d) { // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// - private boolean instQuantifiersWithQueries() { - return StrategyProperties.QUANTIFIERS_INSTANTIATE - .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); - } - - private boolean quantifiersMightSplit() { - return StrategyProperties.QUANTIFIERS_INSTANTIATE - .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)) - || StrategyProperties.QUANTIFIERS_NON_SPLITTING_WITH_PROGS.equals( - strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); - } - - private Feature allowQuantifierSplitting() { - if (StrategyProperties.QUANTIFIERS_INSTANTIATE.equals( - strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY))) { - return longConst(0); - } - if (StrategyProperties.QUANTIFIERS_NON_SPLITTING_WITH_PROGS.equals( - strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY))) { - return sequentContainsNoPrograms(); - } - return inftyConst(); - } - - private boolean quantifierInstantiatedEnabled() { - return !StrategyProperties.QUANTIFIERS_NONE - .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); - } - private boolean classAxiomDelayedApplication() { String classAxiomSetting = strategyProperties.getProperty(StrategyProperties.CLASS_AXIOM_OPTIONS_KEY); @@ -501,338 +351,6 @@ private boolean autoInductionLemmaEnabled() { // chrisg */ } - private Feature allowSplitting(ProjectionToTerm focus) { - if (normalSplitting()) { - return longConst(0); - } - if (StrategyProperties.SPLITTING_DELAYED - .equals(strategyProperties.getProperty(StrategyProperties.SPLITTING_OPTIONS_KEY))) { - return or(applyTF(focus, ContainsExecutableCodeTermFeature.PROGRAMS), - sequentContainsNoPrograms()); - } - // else: SPLITTING_OFF - return applyTF(focus, ContainsExecutableCodeTermFeature.PROGRAMS); - } - - private boolean normalSplitting() { - return StrategyProperties.SPLITTING_NORMAL - .equals(strategyProperties.getProperty(StrategyProperties.SPLITTING_OPTIONS_KEY)); - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // Application of beta- and cut-rules to handle disjunctions - // - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - - private void setupSplitting(RuleSetDispatchFeature d) { - final TermBuffer subFor = new TermBuffer(); - final Feature noCutsAllowed = - sum(subFor, AllowedCutPositionsGenerator.INSTANCE, not(applyTF(subFor, ff.cutAllowed))); - bindRuleSet(d, "beta", - SumFeature.createSum(noCutsAllowed, - ifZero(PurePosDPathFeature.INSTANCE, longConst(-200)), - ScaleFeature.createScaled(CountPosDPathFeature.INSTANCE, -3.0), - ScaleFeature.createScaled(CountMaxDPathFeature.INSTANCE, 10.0), longConst(20))); - TermBuffer superF = new TermBuffer(); - final ProjectionToTerm splitCondition = sub(FocusProjection.INSTANCE, 0); - bindRuleSet(d, "split_cond", add(// do not split over formulas containing auxiliary - // variables - applyTF(FocusProjection.INSTANCE, - rec(any(), not(selectSkolemConstantTermFeature()))), - // prefer splits when condition has quantifiers (less - // likely to be simplified away) - applyTF(splitCondition, - rec(ff.quantifiedFor, ifZero(ff.quantifiedFor, longTermConst(-10)))), - FindDepthFeature.getInstance(), // prefer top level splits - ScaleFeature.createAffine(countOccurrences(splitCondition), -10, 10), - sum(superF, SuperTermGenerator.upwards(any(), getServices()), - applyTF(superF, not(ff.elemUpdate))), - ifZero(applyTF(FocusProjection.INSTANCE, ContainsExecutableCodeTermFeature.PROGRAMS), - longConst(-100), longConst(25)))); - ProjectionToTerm cutFormula = instOf("cutFormula"); - Feature countOccurrencesInSeq = - ScaleFeature.createAffine(countOccurrences(cutFormula), -10, 10); - bindRuleSet(d, "cut_direct", - SumFeature - .createSum( - not(TopLevelFindFeature.ANTEC_OR_SUCC_WITH_UPDATE), - AllowedCutPositionFeature.INSTANCE, - ifZero(notBelowQuantifier(), - add( - applyTF(cutFormula, add(ff.cutAllowed, - // do not cut over formulas containing - // auxiliary variables - rec(any(), not(selectSkolemConstantTermFeature())))), - // prefer cuts over "something = null" - ifZero(applyTF(FocusProjection.INSTANCE, - opSub(tf.eq, any(), vf.nullTerm)), - longConst(-5), longConst(0)), - // punish cuts over formulas containing anon heap functions - ifZero(applyTF(cutFormula, rec(any(), not(anonHeapTermFeature()))), - longConst(0), longConst(1000)), - countOccurrencesInSeq, // standard costs - longConst(100)), - SumFeature // check for cuts below quantifiers - .createSum(applyTF(cutFormula, ff.cutAllowedBelowQuantifier), - applyTF(FocusFormulaProjection.INSTANCE, - ff.quantifiedClauseSet), - ifZero(allowQuantifierSplitting(), longConst(0), - longConst(100)))))); - } - - private void setupSplittingApproval(RuleSetDispatchFeature d) { - bindRuleSet(d, "beta", allowSplitting(FocusFormulaProjection.INSTANCE)); - - bindRuleSet(d, "split_cond", allowSplitting(FocusProjection.INSTANCE)); - - final TermBuffer subFor = new TermBuffer(); - final Feature compareCutAllowed = ifZero(applyTF(subFor, ff.cutAllowed), - leq(applyTF("cutFormula", ff.cutPriority), applyTF(subFor, ff.cutPriority))); - - final Feature noBetterCut = - sum(subFor, AllowedCutPositionsGenerator.INSTANCE, compareCutAllowed); - - bindRuleSet(d, "cut_direct", add(allowSplitting(FocusFormulaProjection.INSTANCE), - ifZero(notBelowQuantifier(), noBetterCut))); - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // Application of equations - // - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - - private void setupApplyEq(RuleSetDispatchFeature d) { - final TermBuffer equation = new TermBuffer(); - final TermBuffer left = new TermBuffer(); - final TermBuffer right = new TermBuffer(); - - // applying equations less deep/less leftish in terms/formulas is - // preferred - // this is important for reducing polynomials (start with the biggest - // summands) - bindRuleSet(d, "apply_equations", - SumFeature.createSum( - ifZero(MatchedAssumesFeature.INSTANCE, - add(CheckApplyEqFeature.INSTANCE, let(equation, AssumptionProjection.create(0), - add(not(applyTF(equation, ff.update)), - // there might be updates in - // front of the assumption - // formula; in this case we wait - // until the updates have - // been applied - let(left, sub(equation, 0), - let(right, sub(equation, 1), - TermSmallerThanFeature.create(right, left))))))), - longConst(-4000))); - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // Normalisation of formulas; this is mostly a pre-processing step for - // handling quantified formulas - // - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - - private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numbers, - LocSetLDT locSetLDT) { - - bindRuleSet(d, "negationNormalForm", add(BelowBinderFeature.getInstance(), - longConst(-500), - ScaleFeature.createScaled(FindDepthFeature.getInstance(), 10.0))); - - bindRuleSet(d, "moveQuantToLeft", - add(quantifiersMightSplit() ? longConst(0) - : applyTF(FocusFormulaProjection.INSTANCE, ff.quantifiedPureLitConjDisj), - longConst(-550))); - - bindRuleSet(d, "conjNormalForm", - ifZero( - add(or(FocusInAntecFeature.getInstance(), notBelowQuantifier()), - NotInScopeOfModalityFeature.INSTANCE), - add(longConst(-150), - ScaleFeature.createScaled(FindDepthFeature.getInstance(), 20)), - inftyConst())); - - bindRuleSet(d, "setEqualityBlastingRight", longConst(-100)); - - bindRuleSet(d, "cnf_setComm", - add(SetsSmallerThanFeature.create(instOf("commRight"), instOf("commLeft"), locSetLDT), - NotInScopeOfModalityFeature.INSTANCE, longConst(-800))); - - bindRuleSet(d, "elimQuantifier", -1000); - bindRuleSet(d, "elimQuantifierWithCast", 50); - - final TermBuffer left = new TermBuffer(); - final TermBuffer right = new TermBuffer(); - bindRuleSet(d, "apply_equations_andOr", - add(let(left, instOf("applyEqLeft"), - let(right, instOf("applyEqRight"), - TermSmallerThanFeature.create(right, left))), - longConst(-150))); - - bindRuleSet(d, "distrQuantifier", - add(or( - applyTF(FocusProjection.INSTANCE, - add(ff.quantifiedClauseSet, not(opSub(Quantifier.ALL, ff.orF)), - EliminableQuantifierTF.INSTANCE)), - SumFeature.createSum(onlyInScopeOfQuantifiers(), - SplittableQuantifiedFormulaFeature.INSTANCE, - ifZero(FocusInAntecFeature.getInstance(), - applyTF(FocusProjection.INSTANCE, sub(ff.andF)), - applyTF(FocusProjection.INSTANCE, sub(ff.orF))))), - longConst(-300))); - - bindRuleSet(d, "swapQuantifiers", - add(applyTF(FocusProjection.INSTANCE, add(ff.quantifiedClauseSet, - EliminableQuantifierTF.INSTANCE, sub(not(EliminableQuantifierTF.INSTANCE)))), - longConst(-300))); - - // category "conjunctive normal form" - - bindRuleSet(d, "cnf_orComm", - SumFeature.createSum(applyTF("commRight", ff.clause), - applyTFNonStrict("commResidue", ff.clauseSet), - or(applyTF("commLeft", ff.andF), - add(applyTF("commLeft", ff.literal), - literalsSmallerThan("commRight", "commLeft", numbers))), - longConst(-100))); - - bindRuleSet(d, "cnf_orAssoc", - SumFeature.createSum(applyTF("assoc0", ff.clause), - applyTF("assoc1", ff.clause), applyTF("assoc2", ff.literal), longConst(-80))); - - bindRuleSet(d, "cnf_andComm", - SumFeature.createSum(applyTF("commLeft", ff.clause), - applyTF("commRight", ff.clauseSet), applyTFNonStrict("commResidue", ff.clauseSet), - // at least one of the subformulas has to be a literal; - // otherwise, sorting is not likely to have any big effect - ifZero( - add(applyTF("commLeft", not(ff.literal)), - applyTF("commRight", rec(ff.andF, not(ff.literal)))), - longConst(100), longConst(-60)), - clausesSmallerThan("commRight", "commLeft", numbers))); - - bindRuleSet(d, "cnf_andAssoc", - SumFeature.createSum(applyTF("assoc0", ff.clauseSet), - applyTF("assoc1", ff.clauseSet), applyTF("assoc2", ff.clause), longConst(-10))); - - bindRuleSet(d, "cnf_dist", - SumFeature.createSum(applyTF("distRight0", ff.clauseSet), - applyTF("distRight1", ff.clauseSet), ifZero(applyTF("distLeft", ff.clause), - longConst(-15), applyTF("distLeft", ff.clauseSet)), - longConst(-35))); - - final TermBuffer superFor = new TermBuffer(); - final Feature onlyBelowQuanAndOr = - sum(superFor, SuperTermGenerator.upwards(any(), getServices()), - applyTF(superFor, or(ff.quantifiedFor, ff.andF, ff.orF))); - - final Feature belowUnskolemisableQuantifier = - ifZero(FocusInAntecFeature.getInstance(), - not(sum(superFor, SuperTermGenerator.upwards(any(), getServices()), - not(applyTF(superFor, op(Quantifier.ALL))))), - not(sum(superFor, SuperTermGenerator.upwards(any(), getServices()), - not(applyTF(superFor, op(Quantifier.EX)))))); - - bindRuleSet(d, "cnf_expandIfThenElse", add( - isBelow(OperatorClassTF.create(Quantifier.class)), - onlyBelowQuanAndOr, belowUnskolemisableQuantifier)); - - final Feature pullOutQuantifierAllowed = - add(isBelow(OperatorClassTF.create(Quantifier.class)), onlyBelowQuanAndOr, applyTF( - FocusProjection.create(0), sub(ff.quantifiedClauseSet, ff.quantifiedClauseSet))); - - bindRuleSet(d, "pullOutQuantifierUnifying", -20); - - bindRuleSet(d, "pullOutQuantifierAll", add(pullOutQuantifierAllowed, - ifZero(FocusInAntecFeature.getInstance(), longConst(-20), longConst(-40)))); - - bindRuleSet(d, "pullOutQuantifierEx", add(pullOutQuantifierAllowed, - ifZero(FocusInAntecFeature.getInstance(), longConst(-40), longConst(-20)))); - } - - private Feature clausesSmallerThan(String smaller, String bigger, IntegerLDT numbers) { - return ClausesSmallerThanFeature.create(instOf(smaller), instOf(bigger), numbers); - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // Heuristic instantiation of quantified formulas - // - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - - private void setupQuantifierInstantiation(RuleSetDispatchFeature d) { - if (quantifierInstantiatedEnabled()) { - final TermBuffer varInst = new TermBuffer(); - final Feature branchPrediction = InstantiationCostScalerFeature - .create(InstantiationCost.create(varInst), allowQuantifierSplitting()); - - bindRuleSet(d, "gamma", - SumFeature.createSum(FocusInAntecFeature.getInstance(), - applyTF(FocusProjection.create(0), - add(ff.quantifiedClauseSet, - instQuantifiersWithQueries() ? longTermConst(0) - : ff.notContainsExecutable)), - forEach(varInst, HeuristicInstantiation.INSTANCE, - add(instantiate("t", varInst), branchPrediction, longConst(10))))); - final TermBuffer splitInst = new TermBuffer(); - - bindRuleSet(d, "triggered", - SumFeature.createSum(forEach(splitInst, TriggeredInstantiations.create(true), - add(instantiateTriggeredVariable(splitInst), longConst(500))), - longConst(1500))); - - } else { - bindRuleSet(d, "gamma", inftyConst()); - bindRuleSet(d, "triggered", inftyConst()); - } - } - - private void setupQuantifierInstantiationApproval(RuleSetDispatchFeature d) { - if (quantifierInstantiatedEnabled()) { - final TermBuffer varInst = new TermBuffer(); - - bindRuleSet(d, "gamma", add(isInstantiated("t"), - not(sum(varInst, HeuristicInstantiation.INSTANCE, not(eq(instOf("t"), varInst)))), - InstantiationCostScalerFeature.create(InstantiationCost.create(instOf("t")), - longConst(0)))); - - final TermBuffer splitInst = new TermBuffer(); - bindRuleSet(d, "triggered", - add(isTriggerVariableInstantiated(), - not(sum(splitInst, TriggeredInstantiations.create(false), - not(eq(instOfTriggerVariable(), splitInst)))))); - } else { - bindRuleSet(d, "gamma", inftyConst()); - bindRuleSet(d, "triggered", inftyConst()); - } - } - - - protected final Feature onlyInScopeOfQuantifiers() { - final TermBuffer buf = new TermBuffer(); - return sum(buf, SuperTermGenerator.upwards(any(), getServices()), - applyTF(buf, ff.quantifiedFor)); - } - - protected Feature notBelowQuantifier() { - final TermBuffer superFor = new TermBuffer(); - return or(TopLevelFindFeature.ANTEC_OR_SUCC, - sum(superFor, SuperTermGenerator.upwards(any(), getServices()), - not(applyTF(superFor, OperatorClassTF.create(Quantifier.class))))); - } - - // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// // @@ -864,8 +382,6 @@ private RuleSetDispatchFeature setupApprovalDispatcher() { bindRuleSet(d, "partialInvAxiom", NonDuplicateAppModPositionFeature.INSTANCE); setupClassAxiomApproval(d); - setupQuantifierInstantiationApproval(d); - setupSplittingApproval(d); bindRuleSet(d, "apply_select_eq", add(isInstantiated("s"), isInstantiated("t1"), @@ -878,12 +394,6 @@ private RuleSetDispatchFeature setupApprovalDispatcher() { add(SimplifiedSelectTermFeature.create(heapLDT), not(ff.ifThenElse)))), not(ContainsTermFeature.create(instOf("s"), instOf("t1"))))); - // Without EqNonDuplicateAppFeature.INSTANCE - // rule 'applyEq' might be applied on the same term - // without changing the sequent for a really long time. This is tested by - // TestSymbolicExecutionTreeBuilder#testInstanceOfNotInEndlessLoop() - bindRuleSet(d, "apply_equations", EqNonDuplicateAppFeature.INSTANCE); - return d; } @@ -937,7 +447,6 @@ private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); - setupQuantifierInstantiation(d); setClassAxiomInstantiation(d); disableInstantiate(); @@ -980,10 +489,10 @@ private void setClassAxiomInstantiation(final RuleSetDispatchFeature d) { * all (it is discarded by the strategy). */ @Override - public > RuleAppCost computeCost(RuleApp app, - PosInOccurrence pio, - Goal goal, - MutableState mState) { + public > RuleAppCost computeCost(@NonNull RuleApp app, + @NonNull PosInOccurrence pio, + @NonNull GOAL goal, + @NonNull MutableState mState) { var time = System.nanoTime(); try { return costComputationF.computeCost(app, pio, goal, mState); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index 691d491ee1..9ae543f686 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java @@ -113,24 +113,6 @@ public class JavaCardDLStrategyFactory implements StrategyFactory { public static final String TOOL_TIP_EXPAND_LOCAL_QUERIES_OFF = "" + "Expansion of local queries is turned off.
" + "This setting is independent of the query treatment setting." + ""; - public static final String TOOL_TIP_QUANTIFIER_NONE = - "" + "Do not instantiate quantified formulas automatically" + ""; - public static final String TOOL_TIP_QUANTIFIER_NO_SPLITS = "" - + "Instantiate quantified formulas automatically
" - + "with terms that occur in a sequent, but only if
" - + "this does not cause proof splitting. Further, quantified
" - + "formulas that contain queries are not instantiated
" + "automatically." + ""; - public static final String TOOL_TIP_QUANTIFIER_NO_SPLITS_WITH_PROGS = - "" + "Instantiate quantified formulas automatically
" - + "with terms that occur in a sequent, but if the
" - + "sequent contains programs then only perform
" - + "instantiations that do not cause proof splitting.
" - + "Further, quantified formulas that contain queries
" - + "are not instantiated automatically." + ""; - public static final String TOOL_TIP_QUANTIFIER_FREE = - "" + "Instantiate quantified formulas automatically
" - + "with terms that occur in a sequent, also if this
" - + "might cause proof splitting." + ""; public static final String TOOL_TIP_AUTO_INDUCTION_ON = "" + "Create an inductive proof for formulas of the form:
" + " ==> \\forall int i; 0<=i->phi
" @@ -208,20 +190,6 @@ private static OneOfStrategyPropertyDefinition getQueryTreatment() { TOOL_TIP_QUERY_OFF)); } - private static OneOfStrategyPropertyDefinition getQuantifierTreatment() { - return new OneOfStrategyPropertyDefinition(StrategyProperties.QUANTIFIERS_OPTIONS_KEY, - "Quantifier treatment", 2, - new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_NONE, "None", - TOOL_TIP_QUANTIFIER_NONE, 2, 4), - new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_NON_SPLITTING, - "No Splits", TOOL_TIP_QUANTIFIER_NO_SPLITS, 6, 2), - new StrategyPropertyValueDefinition( - StrategyProperties.QUANTIFIERS_NON_SPLITTING_WITH_PROGS, "No Splits with Progs", - TOOL_TIP_QUANTIFIER_NO_SPLITS_WITH_PROGS, 2, 4), - new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_INSTANTIATE, "Free", - TOOL_TIP_QUANTIFIER_FREE, 6, 2)); - } - private static OneOfStrategyPropertyDefinition getClassAxiom() { return new OneOfStrategyPropertyDefinition(StrategyProperties.CLASS_AXIOM_OPTIONS_KEY, "Class axiom rule", @@ -261,12 +229,10 @@ public StrategySettingsDefinition getSettingsDefinition() { final OneOfStrategyPropertyDefinition proofSplitting = getProofSplitting(); final OneOfStrategyPropertyDefinition dependencyContracts = getDependencyContracts(); final OneOfStrategyPropertyDefinition queryTreatment = getQueryTreatment(); - final OneOfStrategyPropertyDefinition quantifierTreatment = getQuantifierTreatment(); final OneOfStrategyPropertyDefinition classAxiom = getClassAxiom(); final OneOfStrategyPropertyDefinition autoInduction = getAutoInduction(); // Model return new StrategySettingsDefinition("Java DL Options", ossUsage, proofSplitting, - dependencyContracts, queryTreatment, quantifierTreatment, - classAxiom, autoInduction); + dependencyContracts, queryTreatment, classAxiom, autoInduction); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 9b7c27db5e..715512a148 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -54,7 +54,7 @@ public ModularJavaDLStrategy(Proof proof, List componen @Override protected RuleSetDispatchFeature getCostDispatcher() { - return null; + return conflictCostDispatcher; } private record StratAndDispatcher(AbstractFeatureStrategy strategy, @@ -85,33 +85,34 @@ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, List value) { switch (rs.name().toString()) { case "order_terms" -> { - var intStrat = value.getFirst(); - var javaDLStrat = value.get(1); + var folStrat = value.getFirst(); + var intStrat = value.get(1); bindRuleSet(d, "order_terms", ifZero(applyTF("commEqLeft", tf.intF), intStrat.getCostDispatcher().remove(rs), - javaDLStrat.getCostDispatcher().remove(rs))); + folStrat.getCostDispatcher().remove(rs))); } case "apply_equations" -> { - var intStrat = value.getFirst(); - var javaDLStrat = value.get(1); + var folStrat = value.getFirst(); + var intStrat = value.get(1); bindRuleSet(d, "apply_equations", ifZero(applyTF(FocusProjection.create(0), tf.intF), intStrat.getCostDispatcher().remove(rs), - javaDLStrat.getCostDispatcher().remove(rs))); + folStrat.getCostDispatcher().remove(rs))); } case "apply_equations_andOr" -> { - var intStrat = value.getFirst(); - var javaDLStrat = value.get(1); + var folStrat = value.getFirst(); + var intStrat = value.get(1); if (quantifierInstantiatedEnabled()) { bindRuleSet(d, "apply_equations_andOr", ifZero(applyTF(FocusProjection.create(0), tf.intF), intStrat.getCostDispatcher().remove(rs), - javaDLStrat.getCostDispatcher().remove(rs))); + folStrat.getCostDispatcher().remove(rs))); } else { bindRuleSet(d, "apply_equations_andOr", inftyConst()); } } + default -> throw new IllegalArgumentException("No resolution defined for " + rs); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java index b5546bcf64..132560da43 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -25,7 +25,7 @@ * @author Kai Wallisch */ public class ModularJavaDLStrategyFactory implements StrategyFactory { - private final List componentFactories = Arrays.asList( + private final List componentFactories = Arrays.asList(new FOLStrategyFactory(), new IntegerStrategyFactory(), new SymExStrategyFactory(), new StringStrategyFactory(), new JavaCardDLStrategyFactory()); diff --git a/key.core/src/test/java/de/uka/ilkd/key/proof/runallproofs/performance/DataRecordingStrategy.java b/key.core/src/test/java/de/uka/ilkd/key/proof/runallproofs/performance/DataRecordingStrategy.java index 301292fd16..9af8750195 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/proof/runallproofs/performance/DataRecordingStrategy.java +++ b/key.core/src/test/java/de/uka/ilkd/key/proof/runallproofs/performance/DataRecordingStrategy.java @@ -44,10 +44,10 @@ class DataRecordingStrategy extends JavaCardDLStrategy { } @Override - public > RuleAppCost computeCost( - RuleApp app, PosInOccurrence pio, - Goal goal, - MutableState mState) { + public > @NonNull RuleAppCost computeCost( + @NonNull RuleApp app, @NonNull PosInOccurrence pio, + @NonNull GOAL goal, + @NonNull MutableState mState) { long begin = System.nanoTime(); RuleAppCost result = super.computeCost(app, pio, goal, mState); long end = System.nanoTime(); @@ -56,8 +56,9 @@ class DataRecordingStrategy extends JavaCardDLStrategy { } @Override - public void instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, - RuleAppCostCollector collector) { + public void instantiateApp(@NonNull RuleApp app, @NonNull PosInOccurrence pio, + @NonNull Goal goal, + @NonNull RuleAppCostCollector collector) { long begin = System.nanoTime(); super.instantiateApp(app, pio, goal, collector); long end = System.nanoTime(); From 50ca4c520c14c499a09bc0f5f336c5a89701f574 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 13 Aug 2025 11:03:52 +0200 Subject: [PATCH 34/62] Nullability --- .../strategy/SymbolicExecutionStrategy.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java index db91ec77ac..e4ac308db6 100644 --- a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java +++ b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java @@ -5,7 +5,6 @@ import java.util.ArrayList; -import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.strategy.JavaCardDLStrategy; @@ -106,7 +105,7 @@ private SymbolicExecutionStrategy(Proof proof, StrategyProperties sp) { * {@inheritDoc} */ @Override - protected Feature setupApprovalF() { + protected @NonNull Feature setupApprovalF() { Feature result = super.setupApprovalF(); // Make sure that cuts are only applied if the cut term is not already part of the sequent. // This check is performed exactly before the rule is applied because the sequent might has @@ -122,17 +121,17 @@ protected Feature setupApprovalF() { * {@inheritDoc} */ @Override - protected Feature setupGlobalF(Feature dispatcher) { + protected @NonNull Feature setupGlobalF(@NonNull Feature dispatcher) { Feature globalF = super.setupGlobalF(dispatcher); // Make sure that modalities without symbolic execution label are executed first because // they might forbid rule application on modalities with symbolic execution label (see loop // body branches) globalF = add(globalF, ifZero(not(new BinaryFeature() { @Override - protected > boolean filter(RuleApp app, - PosInOccurrence pos, Goal goal, MutableState mState) { + protected > boolean filter(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { return pos != null - && SymbolicExecutionUtil.hasSymbolicExecutionLabel((JTerm) pos.subTerm()); + && SymbolicExecutionUtil.hasSymbolicExecutionLabel(pos.subTerm()); } }), longConst(-3000))); // Make sure that the modality which executes a loop body is preferred against the @@ -141,9 +140,9 @@ protected Feature setupGlobalF(Feature dispatcher) { add(globalF, ifZero(add(new Feature() { @Override - public > RuleAppCost computeCost( + public > RuleAppCost computeCost( RuleApp app, PosInOccurrence pos, - Goal goal, MutableState mState) { + GOAL goal, MutableState mState) { return pos != null ? cost(0) : TopRuleAppCost.INSTANCE; } }, @@ -302,7 +301,7 @@ public static class Factory implements StrategyFactory { * {@inheritDoc} */ @Override - public StrategySettingsDefinition getSettingsDefinition() { + public @NonNull StrategySettingsDefinition getSettingsDefinition() { // Properties OneOfStrategyPropertyDefinition methodTreatment = new OneOfStrategyPropertyDefinition( StrategyProperties.METHOD_OPTIONS_KEY, "Method Treatment", From 40a5c311c0351407c87a142e652dd7bd72d95182 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 13 Aug 2025 12:37:01 +0200 Subject: [PATCH 35/62] Remove LocSet handling from FOLStrat --- .../de/uka/ilkd/key/strategy/FOLStrategy.java | 16 +++++----------- .../ilkd/key/strategy/JavaCardDLStrategy.java | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index e4656866b9..77b9bb1c48 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -4,7 +4,6 @@ package de.uka.ilkd.key.strategy; import de.uka.ilkd.key.ldt.IntegerLDT; -import de.uka.ilkd.key.ldt.LocSetLDT; import de.uka.ilkd.key.logic.op.Equality; import de.uka.ilkd.key.logic.op.Junctor; import de.uka.ilkd.key.logic.op.Quantifier; @@ -73,7 +72,6 @@ public FOLStrategy(Proof proof, StrategyProperties strategyProperties) { } private RuleSetDispatchFeature setupCostComputationF() { - final LocSetLDT locSetLDT = getServices().getTypeConverter().getLocSetLDT(); final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); @@ -146,7 +144,7 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "cut", not(isInstantiated("cutFormula"))); if (quantifierInstantiatedEnabled()) { - setupFormulaNormalisation(d, numbers, locSetLDT); + setupFormulaNormalisation(d, numbers); } else { bindRuleSet(d, "negationNormalForm", inftyConst()); bindRuleSet(d, "moveQuantToLeft", inftyConst()); @@ -249,12 +247,10 @@ public Name name() { // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// - private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numbers, - LocSetLDT locSetLDT) { - + private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numbers) { bindRuleSet(d, "negationNormalForm", add(BelowBinderFeature.getInstance(), longConst(-500), - ScaleFeature.createScaled(FindDepthFeature.getInstance(), 10.0))); + ScaleFeature.createScaled(FindDepthFeature.getInstance(), 10.0))); bindRuleSet(d, "moveQuantToLeft", add(quantifiersMightSplit() ? longConst(0) @@ -266,14 +262,12 @@ private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numb add(or(FocusInAntecFeature.getInstance(), notBelowQuantifier()), NotInScopeOfModalityFeature.INSTANCE), add(longConst(-150), - ScaleFeature.createScaled(FindDepthFeature.getInstance(), 20)), + ScaleFeature.createScaled(FindDepthFeature.getInstance(), 20)), inftyConst())); bindRuleSet(d, "setEqualityBlastingRight", longConst(-100)); - bindRuleSet(d, "cnf_setComm", - add(SetsSmallerThanFeature.create(instOf("commRight"), instOf("commLeft"), locSetLDT), - NotInScopeOfModalityFeature.INSTANCE, longConst(-800))); + bindRuleSet(d, "elimQuantifier", -1000); bindRuleSet(d, "elimQuantifierWithCast", 50); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 8087f0a10e..3bba99f2a9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicLong; import de.uka.ilkd.key.ldt.HeapLDT; +import de.uka.ilkd.key.ldt.LocSetLDT; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.UseDependencyContractRule; @@ -159,6 +160,19 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "test_gen_quan", inftyConst()); bindRuleSet(d, "test_gen_quan_num", inftyConst()); + // This is moved here instead of FOLStrategy, because it deals only w/ loc sets + if (!StrategyProperties.QUANTIFIERS_NONE + .equals( + strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY))) { + final LocSetLDT locSetLDT = getServices().getTypeConverter().getLocSetLDT(); + bindRuleSet(d, "cnf_setComm", + add(SetsSmallerThanFeature.create(instOf("commRight"), instOf("commLeft"), + locSetLDT), + NotInScopeOfModalityFeature.INSTANCE, longConst(-800))); + } else { + bindRuleSet(d, "cnf_setComm", inftyConst()); + } + bindRuleSet(d, "simplify_literals", // ifZero ( ConstraintStrengthenFeatureUC.create(proof), // longConst ( 0 ), From dc08d1b8cb35feae3e5aa7b6087e19f03d0f44f5 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 13 Aug 2025 12:52:22 +0200 Subject: [PATCH 36/62] Add JFOLStrat --- .../de/uka/ilkd/key/strategy/FOLStrategy.java | 45 ++---------- .../ilkd/key/strategy/FOLStrategyFactory.java | 2 +- .../uka/ilkd/key/strategy/JFOLStrategy.java | 69 +++++++++++++++++++ 3 files changed, 75 insertions(+), 41 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index 77b9bb1c48..d625d8a2f7 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -3,7 +3,6 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import de.uka.ilkd.key.ldt.IntegerLDT; import de.uka.ilkd.key.logic.op.Equality; import de.uka.ilkd.key.logic.op.Junctor; import de.uka.ilkd.key.logic.op.Quantifier; @@ -48,9 +47,8 @@ public class FOLStrategy extends AbstractFeatureStrategy { private final Feature approvalF; private final Feature instantiationF; - private final ArithTermFeatures tf; - private final FormulaTermFeatures ff; - private final ValueTermFeature vf; + protected final ArithTermFeatures tf; + protected final FormulaTermFeatures ff; public FOLStrategy(Proof proof, StrategyProperties strategyProperties) { super(proof); @@ -59,8 +57,6 @@ public FOLStrategy(Proof proof, StrategyProperties strategyProperties) { this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); this.ff = new FormulaTermFeatures(this.tf); - var heapLDT = getServices().getTypeConverter().getHeapLDT(); - vf = new ValueTermFeature(op(heapLDT.getNull())); costComputationDispatcher = setupCostComputationF(); approvalDispatcher = setupApprovalDispatcher(); @@ -72,7 +68,6 @@ public FOLStrategy(Proof proof, StrategyProperties strategyProperties) { } private RuleSetDispatchFeature setupCostComputationF() { - final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); bindRuleSet(d, "closure", -15000); @@ -144,7 +139,7 @@ private RuleSetDispatchFeature setupCostComputationF() { bindRuleSet(d, "cut", not(isInstantiated("cutFormula"))); if (quantifierInstantiatedEnabled()) { - setupFormulaNormalisation(d, numbers); + setupFormulaNormalisation(d); } else { bindRuleSet(d, "negationNormalForm", inftyConst()); bindRuleSet(d, "moveQuantToLeft", inftyConst()); @@ -247,7 +242,7 @@ public Name name() { // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// - private void setupFormulaNormalisation(RuleSetDispatchFeature d, IntegerLDT numbers) { + protected void setupFormulaNormalisation(RuleSetDispatchFeature d) { bindRuleSet(d, "negationNormalForm", add(BelowBinderFeature.getInstance(), longConst(-500), ScaleFeature.createScaled(FindDepthFeature.getInstance(), 10.0))); @@ -299,29 +294,10 @@ EliminableQuantifierTF.INSTANCE, sub(not(EliminableQuantifierTF.INSTANCE)))), // category "conjunctive normal form" - bindRuleSet(d, "cnf_orComm", - SumFeature.createSum(applyTF("commRight", ff.clause), - applyTFNonStrict("commResidue", ff.clauseSet), - or(applyTF("commLeft", ff.andF), - add(applyTF("commLeft", ff.literal), - literalsSmallerThan("commRight", "commLeft", numbers))), - longConst(-100))); - bindRuleSet(d, "cnf_orAssoc", SumFeature.createSum(applyTF("assoc0", ff.clause), applyTF("assoc1", ff.clause), applyTF("assoc2", ff.literal), longConst(-80))); - bindRuleSet(d, "cnf_andComm", - SumFeature.createSum(applyTF("commLeft", ff.clause), - applyTF("commRight", ff.clauseSet), applyTFNonStrict("commResidue", ff.clauseSet), - // at least one of the subformulas has to be a literal; - // otherwise, sorting is not likely to have any big effect - ifZero( - add(applyTF("commLeft", not(ff.literal)), - applyTF("commRight", rec(ff.andF, not(ff.literal)))), - longConst(100), longConst(-60)), - clausesSmallerThan("commRight", "commLeft", numbers))); - bindRuleSet(d, "cnf_andAssoc", SumFeature.createSum(applyTF("assoc0", ff.clauseSet), applyTF("assoc1", ff.clauseSet), applyTF("assoc2", ff.clause), longConst(-10))); @@ -361,10 +337,6 @@ EliminableQuantifierTF.INSTANCE, sub(not(EliminableQuantifierTF.INSTANCE)))), ifZero(FocusInAntecFeature.getInstance(), longConst(-40), longConst(-20)))); } - private Feature clausesSmallerThan(String smaller, String bigger, IntegerLDT numbers) { - return ClausesSmallerThanFeature.create(instOf(smaller), instOf(bigger), numbers); - } - // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// // @@ -456,7 +428,7 @@ private void setupReplaceKnown(RuleSetDispatchFeature d) { // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// - private void setupSplitting(RuleSetDispatchFeature d) { + protected void setupSplitting(RuleSetDispatchFeature d) { final TermBuffer subFor = new TermBuffer(); final Feature noCutsAllowed = sum(subFor, AllowedCutPositionsGenerator.INSTANCE, not(applyTF(subFor, ff.cutAllowed))); @@ -495,13 +467,6 @@ private void setupSplitting(RuleSetDispatchFeature d) { // do not cut over formulas containing // auxiliary variables rec(any(), not(selectSkolemConstantTermFeature())))), - // prefer cuts over "something = null" - ifZero(applyTF(FocusProjection.INSTANCE, - opSub(tf.eq, any(), vf.nullTerm)), - longConst(-5), longConst(0)), - // punish cuts over formulas containing anon heap functions - ifZero(applyTF(cutFormula, rec(any(), not(anonHeapTermFeature()))), - longConst(0), longConst(1000)), countOccurrencesInSeq, // standard costs longConst(100)), SumFeature // check for cuts below quantifiers diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java index 85665c6fc5..5487117dd5 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java @@ -35,7 +35,7 @@ public class FOLStrategyFactory implements StrategyFactory { @Override public Strategy<@NonNull Goal> create(Proof proof, StrategyProperties strategyProperties) { - return new FOLStrategy(proof, strategyProperties); + return new JFOLStrategy(proof, strategyProperties); } private static OneOfStrategyPropertyDefinition getQuantifierTreatment() { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java new file mode 100644 index 0000000000..4d4d1fbbd9 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java @@ -0,0 +1,69 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import de.uka.ilkd.key.ldt.IntegerLDT; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; +import de.uka.ilkd.key.strategy.quantifierHeuristics.ClausesSmallerThanFeature; +import de.uka.ilkd.key.strategy.termProjection.FocusProjection; + +import org.key_project.prover.strategy.costbased.feature.Feature; +import org.key_project.prover.strategy.costbased.feature.SumFeature; +import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; + +public class JFOLStrategy extends FOLStrategy { + + public JFOLStrategy(Proof proof, StrategyProperties strategyProperties) { + super(proof, strategyProperties); + } + + @Override + protected void setupFormulaNormalisation(RuleSetDispatchFeature d) { + super.setupFormulaNormalisation(d); + var numbers = getServices().getTypeConverter().getIntegerLDT(); + bindRuleSet(d, "cnf_orComm", + SumFeature.createSum(applyTF("commRight", ff.clause), + applyTFNonStrict("commResidue", ff.clauseSet), + or(applyTF("commLeft", ff.andF), + add(applyTF("commLeft", ff.literal), + literalsSmallerThan("commRight", "commLeft", numbers))), + longConst(-100))); + bindRuleSet(d, "cnf_andComm", + SumFeature.createSum(applyTF("commLeft", ff.clause), + applyTF("commRight", ff.clauseSet), applyTFNonStrict("commResidue", ff.clauseSet), + // at least one of the subformulas has to be a literal; + // otherwise, sorting is not likely to have any big effect + ifZero( + add(applyTF("commLeft", not(ff.literal)), + applyTF("commRight", rec(ff.andF, not(ff.literal)))), + longConst(100), longConst(-60)), + clausesSmallerThan("commRight", "commLeft", numbers))); + } + + @Override + protected void setupSplitting(RuleSetDispatchFeature d) { + super.setupSplitting(d); + var heapLDT = getServices().getTypeConverter().getHeapLDT(); + var vf = new ValueTermFeature(op(heapLDT.getNull())); + ProjectionToTerm cutFormula = instOf("cutFormula"); + bindRuleSet(d, "cut_direct", + SumFeature + .createSum( + ifZero(notBelowQuantifier(), + add( + // prefer cuts over "something = null" + ifZero(applyTF(FocusProjection.INSTANCE, + opSub(tf.eq, any(), vf.nullTerm)), + longConst(-5), longConst(0)), + // punish cuts over formulas containing anon heap functions + ifZero(applyTF(cutFormula, rec(any(), not(anonHeapTermFeature()))), + longConst(0), longConst(1000)))))); + } + + private Feature clausesSmallerThan(String smaller, String bigger, IntegerLDT numbers) { + return ClausesSmallerThanFeature.create(instOf(smaller), instOf(bigger), numbers); + } +} From bd2caaf24033964a6fabd9f93c2c474cb44d6ee0 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 16 Oct 2025 14:01:52 +0200 Subject: [PATCH 37/62] Split up int rules; fix relative paths in JARs --- .../java/de/uka/ilkd/key/nparser/KeyAst.java | 4 +- .../uka/ilkd/key/nparser/ParsingFacade.java | 9 +- .../key/nparser/builder/IncludeFinder.java | 19 ++-- .../de/uka/ilkd/key/proof/io/KeYFile.java | 2 +- .../uka/ilkd/key/proof/io/UrlRuleSource.java | 9 +- .../key/proof/rules/{ => integer}/bigint.key | 0 .../rules/{ => integer}/binaryAxioms.key | 0 .../rules/{ => integer}/binaryLemmas.key | 0 .../key/proof/rules/{ => integer}/bprod.key | 0 .../key/proof/rules/{ => integer}/bsum.key | 0 .../key/proof/rules/{ => integer}/intDiv.key | 0 .../key/proof/rules/{ => integer}/intPow.key | 0 .../proof/rules/{ => integer}/intRules.key | 0 .../intRulesCheckedSemantics.key | 0 .../{ => integer}/intRulesJavaSemantics.key | 0 .../intRulesUncheckedSemantics.key | 0 .../integerAssignment2UpdateRules.key | 0 .../key/proof/rules/integer/integerHeader.key | 97 +++++++++++++++++++ .../{ => integer}/integerRulesCommon.key | 0 .../integerSimplificationRules.key | 0 .../javaIntegerHeader.key} | 91 ----------------- .../de/uka/ilkd/key/proof/rules/ldt.key | 3 +- .../ilkd/key/proof/rules/standardRules.key | 24 ++--- 23 files changed, 138 insertions(+), 120 deletions(-) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/bigint.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/binaryAxioms.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/binaryLemmas.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/bprod.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/bsum.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/intDiv.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/intPow.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/intRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/intRulesCheckedSemantics.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/intRulesJavaSemantics.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/intRulesUncheckedSemantics.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/integerAssignment2UpdateRules.key (100%) create mode 100644 key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerHeader.key rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/integerRulesCommon.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => integer}/integerSimplificationRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{integerHeader.key => integer/javaIntegerHeader.key} (66%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/KeyAst.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/KeyAst.java index cc452f8ba8..620fde224e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/KeyAst.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/KeyAst.java @@ -5,7 +5,7 @@ import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; +import java.nio.file.Path; import java.util.List; import de.uka.ilkd.key.nparser.builder.BuilderHelpers; @@ -117,7 +117,7 @@ public ProofSettings findProofSettings() { return null; } - public Includes getIncludes(URL base) { + public Includes getIncludes(Path base) { IncludeFinder finder = new IncludeFinder(base); accept(finder); return finder.getIncludes(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java index e06db61d96..695616b2aa 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java @@ -6,6 +6,7 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; @@ -70,7 +71,13 @@ public static List parseFiles(URL url) throws IOException { reached.add(url); KeyAst.File ctx = parseFile(url); ctxs.add(ctx); - Collection includes = ctx.getIncludes(url).getRuleSets(); + Path path = null; + try { + path = Path.of(url.toURI()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + Collection includes = ctx.getIncludes(path).getRuleSets(); for (RuleSource u : includes) { if (!reached.contains(u.url())) { queue.push(u.url()); diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java index 040a52fb95..09f21f24d2 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java @@ -5,7 +5,9 @@ import java.io.File; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; +import java.nio.file.Path; import de.uka.ilkd.key.nparser.KeYParser; import de.uka.ilkd.key.proof.init.Includes; @@ -22,15 +24,12 @@ * @see #getIncludes() */ public class IncludeFinder extends AbstractBuilder { - private final URL base; + private final Path base; private final Includes includes = new Includes(); - private final String basePath; private boolean ldt = false; - public IncludeFinder(URL base) { + public IncludeFinder(Path base) { this.base = base; - String a = base.getPath(); - basePath = a.substring(0, a.lastIndexOf('/')); } @Override @@ -61,9 +60,13 @@ private void addInclude(String filename, boolean relativePath) throws MalformedU filename = filename.replace('/', File.separatorChar); // Not required for Windows, but // whatsoever filename = filename.replace('\\', File.separatorChar); // Special handling for Linux - URL path = new URL(base.getProtocol(), base.getHost(), base.getPort(), - basePath + "/" + filename); - source = RuleSourceFactory.initRuleFile(path); + var path = base.resolve(filename).normalize(); + var uri = URI.create(path.toString()); + if (uri.getScheme() == null) { + uri = URI.create("file:///" + path); + } + URL url = uri.toURL(); + source = RuleSourceFactory.initRuleFile(url); } else { source = RuleSourceFactory.fromDefaultLocation(filename); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/KeYFile.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/KeYFile.java index a61f882c9b..45279d29c0 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/KeYFile.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/KeYFile.java @@ -219,7 +219,7 @@ public Includes readIncludes() throws ProofInputException { if (includes == null) { try { KeyAst.File ctx = getParseContext(); - includes = ctx.getIncludes(file.file().getParent().toUri().toURL()); + includes = ctx.getIncludes(file.file().getParent()); } catch (ParseCancellationException e) { throw new ParseCancellationException(e); } catch (Exception e) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/UrlRuleSource.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/UrlRuleSource.java index 5d3a19b03f..f921f77d6e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/UrlRuleSource.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/UrlRuleSource.java @@ -61,10 +61,11 @@ public Path file() { try { return Paths.get(uri); } catch (FileSystemNotFoundException e) { - URI rootFs = URI.create(StringUtil.takeUntil(uri.toString(), "!")); - String internal = StringUtil.takeAfter(uri.toString(), "!"); - FileSystem zipfs = FileSystems.newFileSystem(rootFs, new HashMap<>()); - return zipfs.getPath(internal); + URI rootFs = URI.create(StringUtil.takeUntil(uri.toString(), "\\!")); + String internal = StringUtil.takeAfter(uri.toString(), "\\!"); + try (FileSystem zipfs = FileSystems.newFileSystem(rootFs, new HashMap<>())) { + return zipfs.getPath(internal); + } } } catch (URISyntaxException | IOException e) { throw new RuntimeException(e); diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/bigint.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/bigint.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/bigint.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/bigint.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/binaryAxioms.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/binaryAxioms.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/binaryAxioms.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/binaryAxioms.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/binaryLemmas.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/binaryLemmas.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/binaryLemmas.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/binaryLemmas.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/bprod.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/bprod.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/bprod.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/bprod.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/bsum.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/bsum.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/bsum.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/bsum.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intDiv.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intDiv.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intDiv.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intDiv.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intPow.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intPow.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intPow.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intPow.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRulesCheckedSemantics.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRulesCheckedSemantics.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRulesCheckedSemantics.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRulesCheckedSemantics.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRulesJavaSemantics.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRulesJavaSemantics.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRulesJavaSemantics.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRulesJavaSemantics.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRulesUncheckedSemantics.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRulesUncheckedSemantics.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/intRulesUncheckedSemantics.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/intRulesUncheckedSemantics.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerAssignment2UpdateRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerAssignment2UpdateRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerAssignment2UpdateRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerAssignment2UpdateRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerHeader.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerHeader.key new file mode 100644 index 0000000000..c605ac1da8 --- /dev/null +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerHeader.key @@ -0,0 +1,97 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ + +\sorts { + numbers; + int; + + // these sort are not axiomatised yet; to come in CHARTER + // they are here included to allow us to load Java program that + // contain some methods or fields of type float or double + + real; // TODO @Real +} + +\functions { + + // ---------------------------------------------------------------------------- + // The functions declared below preserve their semantics independently + // from the current integer semantics. + // ---------------------------------------------------------------------------- + + numbers #; + numbers 0(numbers); + numbers 1(numbers); + numbers 2(numbers); + numbers 3(numbers); + numbers 4(numbers); + numbers 5(numbers); + numbers 6(numbers); + numbers 7(numbers); + numbers 8(numbers); + numbers 9(numbers); + numbers neglit(numbers); + + int Z(numbers); + + // arithmetic operators on mathematical integers + int add(int, int); + int neg(int); + int sub(int, int); + int mul(int, int); + int div(int, int); + int mod(int, int); + int pow(int, int); + int log(int, int); + + // comprehensions + int bsum {false, false, true}(int, int, int); + int bprod {false, false, true}(int, int, int); + int sum {true, true}(boolean, int); + int prod {true, true}(boolean, int); + int min {true, true}(boolean, int); + int max {true, true}(boolean, int); + + // functions to indicate undefinedness + int undefinedPow(int, int); + int undefinedLog(int, int); + + // arithmetic operators with modulo semantics + int jmod(int, int); + int jdiv(int, int); + + // shift operations + + // left '>>' right + int shiftright(/* left */ int, /* right */ int); + // left '<<' right + int shiftleft(/* left */ int, /* right */ int); + + // left '>>' right with right >= 0 + int shiftrightPositiveShift(/* left */ int, /* right */ int); + // left '<<' right with right >= 0 + int shiftleftPositiveShift(/* left */ int, /* right */ int); + + // unsignedshift for arbitrary length bitvectors does not make much sense + // therefore only a version with an explicit bitvector size is supported + int unsignedshift(/* left */ int, /* right */ int, /* bitsize */ int); + + // bitmask operations &, |, ^ + int binaryAnd(/* left */ int, /* right */ int); + int binaryOr(/* left */ int, /* right */ int); + int binaryXOr(/* left */ int, /* right */ int); +} + +\predicates { + + // ---------------------------------------------------------------------------- + // The predicates declared below preserve their semantics independently + // from the current integer semantics. + // ---------------------------------------------------------------------------- + + leq(int, int); + lt(int, int); + geq(int, int); + gt(int, int); +} diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerRulesCommon.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerRulesCommon.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerRulesCommon.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerRulesCommon.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerSimplificationRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerSimplificationRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/integerSimplificationRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerHeader.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/javaIntegerHeader.key similarity index 66% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerHeader.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/javaIntegerHeader.key index 73337d3d4d..4e76e26fba 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integerHeader.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/integer/javaIntegerHeader.key @@ -1,59 +1,6 @@ -/* This file is part of KeY - https://key-project.org - * KeY is licensed under the GNU General Public License Version 2 - * SPDX-License-Identifier: GPL-2.0-only */ - -\sorts { - numbers; - int; - - // these sort are not axiomatised yet; to come in CHARTER - // they are here included to allow us to load Java program that - // contain some methods or fields of type float or double - - real; // TODO @Real -} - \functions { - - // ---------------------------------------------------------------------------- - // The functions declared below preserve their semantics independently - // from the current integer semantics. - // ---------------------------------------------------------------------------- - - numbers #; - numbers 0(numbers); - numbers 1(numbers); - numbers 2(numbers); - numbers 3(numbers); - numbers 4(numbers); - numbers 5(numbers); - numbers 6(numbers); - numbers 7(numbers); - numbers 8(numbers); - numbers 9(numbers); - numbers neglit(numbers); - - int Z(numbers); int C(numbers); - // arithmetic operators on mathematical integers - int add(int, int); - int neg(int); - int sub(int, int); - int mul(int, int); - int div(int, int); - int mod(int, int); - int pow(int, int); - int log(int, int); - - // comprehensions - int bsum {false, false, true}(int, int, int); - int bprod {false, false, true}(int, int, int); - int sum {true, true}(boolean, int); - int prod {true, true}(boolean, int); - int min {true, true}(boolean, int); - int max {true, true}(boolean, int); - // max and min constants int byte_MAX; int byte_MIN; @@ -77,10 +24,6 @@ int short_HALFRANGE; int short_RANGE; - // functions to indicate undefinedness - int undefinedPow(int, int); - int undefinedLog(int, int); - // functions to indicate overflows int javaUnaryMinusIntOverFlow(int); int javaUnaryMinusLongOverFlow(int); @@ -102,8 +45,6 @@ int javaCastCharOverFlow(int); // arithmetic operators with modulo semantics - int jmod(int, int); - int jdiv(int, int); int unaryMinusJint(int); int unaryMinusJlong(int); int addJint(int, int); @@ -126,22 +67,6 @@ int bitwiseNegateJint(int); int bitwiseNegateJlong(int); - // shift operations - - // left '>>' right - int shiftright(/* left */ int, /* right */ int); - // left '<<' right - int shiftleft(/* left */ int, /* right */ int); - - // left '>>' right with right >= 0 - int shiftrightPositiveShift(/* left */ int, /* right */ int); - // left '<<' right with right >= 0 - int shiftleftPositiveShift(/* left */ int, /* right */ int); - - // unsignedshift for arbitrary length bitvectors does not make much sense - // therefore only a version with an explicit bitvector size is supported - int unsignedshift(/* left */ int, /* right */ int, /* bitsize */ int); - // bitvector operations as in Java with bitvector sizes 32 (int) and 64 (long) // right op only the lower 5 bits/6 bits (i.e., range is always 0..31 inclusive for int and 0..63 incl. for long int shiftrightJint(int, int); @@ -153,11 +78,6 @@ int unsignedshiftrightJint(int, int); int unsignedshiftrightJlong(int, int); - // bitmask operations &, |, ^ - int binaryAnd(/* left */ int, /* right */ int); - int binaryOr(/* left */ int, /* right */ int); - int binaryXOr(/* left */ int, /* right */ int); - // bitmask operations for Java int orJint(int, int); int orJlong(int, int); @@ -236,17 +156,6 @@ } \predicates { - - // ---------------------------------------------------------------------------- - // The predicates declared below preserve their semantics independently - // from the current integer semantics. - // ---------------------------------------------------------------------------- - - leq(int, int); - lt(int, int); - geq(int, int); - gt(int, int); - // ---------------------------------------------------------------------------- // The functions declared below change their semantics when switching the // used integer semantics. diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key index d54f2527f0..594382b8b0 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key @@ -16,7 +16,8 @@ ruleSetsDeclarations, soundDefaultContracts, boolean, - integerHeader, + "./integer/integerHeader", + "./integer/javaIntegerHeader", javaHeader, floatHeader, heap, diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key index 90e8d1940c..7ed6040816 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key @@ -17,16 +17,16 @@ \include updateRules; // integer rules -\include integerRulesCommon; -\include intRules, - intRulesUncheckedSemantics, - intRulesCheckedSemantics, - intRulesJavaSemantics; -\include integerSimplificationRules; -\include intDiv; -\include bsum, bprod; -\include binaryAxioms, binaryLemmas; -\include intPow; +\include "./integer/integerRulesCommon"; +\include "./integer/intRules", + "./integer/intRulesUncheckedSemantics", + "./integer/intRulesCheckedSemantics", + "./integer/intRulesJavaSemantics"; +\include "./integer/integerSimplificationRules"; +\include "./integer/intDiv"; +\include "./integer/bsum", "./integer/bprod"; +\include "./integer/binaryAxioms", "./integer/binaryLemmas"; +\include "./integer/intPow"; // float rules \include floatRulesCommon; @@ -54,9 +54,9 @@ \include activeUse; \include instanceAllocation; \include java5; -\include integerAssignment2UpdateRules; +\include "./integer/integerAssignment2UpdateRules"; \include floatAssignment2UpdateRules; -\include bigint; +\include "./integer/bigint"; \include adtProgramDecompositionRules; // wellfounded relation From ab5073adc7dfb8fd6febc6d210782c3f012ed1ff Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 16 Oct 2025 14:08:44 +0200 Subject: [PATCH 38/62] Split sequence --- .../main/resources/de/uka/ilkd/key/proof/rules/ldt.key | 2 +- .../de/uka/ilkd/key/proof/rules/{ => sequence}/seq.key | 0 .../ilkd/key/proof/rules/{ => sequence}/seqCoreRules.key | 0 .../de/uka/ilkd/key/proof/rules/{ => sequence}/seqEq.key | 0 .../uka/ilkd/key/proof/rules/{ => sequence}/seqPerm.key | 0 .../uka/ilkd/key/proof/rules/{ => sequence}/seqPerm2.key | 0 .../uka/ilkd/key/proof/rules/{ => sequence}/seqRules.key | 0 .../de/uka/ilkd/key/proof/rules/standardRules.key | 8 ++++---- 8 files changed, 5 insertions(+), 5 deletions(-) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => sequence}/seq.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => sequence}/seqCoreRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => sequence}/seqEq.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => sequence}/seqPerm.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => sequence}/seqPerm2.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => sequence}/seqRules.key (100%) diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key index 594382b8b0..2cff1b7667 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key @@ -24,7 +24,7 @@ locSets, permission, reach, - seq, + "./sequence/seq", map, freeADT, wellfound, diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seq.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seq.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seq.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seq.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqCoreRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqCoreRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqCoreRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqCoreRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqEq.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqEq.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqEq.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqEq.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqPerm.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqPerm.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqPerm.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqPerm.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqPerm2.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqPerm2.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqPerm2.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqPerm2.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/seqRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/sequence/seqRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key index 7ed6040816..34a20b6cb0 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key @@ -44,9 +44,9 @@ \include heapRules; \include permissionRules; \include reachRules; -\include seqCoreRules, seqRules; -\include seqPerm; -\include seqPerm2; +\include "./sequence/seqCoreRules", "./sequence/seqRules"; +\include "./sequence/seqPerm"; +\include "./sequence/seqPerm2"; // rules for Java (order does not matter, since not provable anyway) \include javaRules; @@ -67,7 +67,7 @@ \include regExTheory; // TODO: fix rules and uncomment // rules for information flow verification -\include seqEq; +\include "./sequence/seqEq"; \include infFlow; // size rules for maps From f263c6a11e5978ff41c84de1a1cdc69f7220ddb9 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 16 Oct 2025 14:32:18 +0200 Subject: [PATCH 39/62] Make paths relative by default; split more rules and headers --- .../key/nparser/builder/IncludeFinder.java | 26 ++++++++----------- .../{ => classicalLogic}/firstOrderRules.key | 0 .../formulaNormalisationRules.key | 0 .../rules/{ => classicalLogic}/propRule.key | 0 .../floatAssignment2UpdateRules.key | 0 .../proof/rules/{ => float}/floatHeader.key | 0 .../proof/rules/{ => float}/floatRules.key | 0 .../{ => float}/floatRulesAssumeStrictfp.key | 0 .../rules/{ => float}/floatRulesCommon.key | 0 .../{ => float}/floatRulesVerifyNormal.key | 0 .../de/uka/ilkd/key/proof/rules/ldt.key | 8 +++--- .../key/proof/rules/{ => locset}/locSets.key | 0 .../proof/rules/{ => locset}/locSetsRules.key | 0 .../rules/{ => permission}/permission.key | 0 .../{ => permission}/permissionRules.key | 0 .../ilkd/key/proof/rules/standardRules.key | 26 +++++++++---------- .../rules/{ => string}/charListHeader.key | 0 .../rules/{ => string}/charListRules.key | 0 .../proof/rules/{ => string}/regExAxioms.key | 0 .../proof/rules/{ => string}/regExHeader.key | 0 .../proof/rules/{ => string}/regExLemma.key | 0 .../rules/{ => string}/regExLemmaProven.key | 0 .../proof/rules/{ => string}/regExTheory.key | 0 .../key/proof/rules/{ => wellDefined}/wd.key | 0 .../{ => wellDefined}/wdFormulaRules.key | 0 .../{ => wellDefined}/wdGeneralRules.key | 0 .../rules/{ => wellDefined}/wdHeader.key | 0 .../rules/{ => wellDefined}/wdHeapRules.key | 0 .../rules/{ => wellDefined}/wdLocSetRules.key | 0 .../{ => wellDefined}/wdNumericalRules.key | 0 .../rules/{ => wellDefined}/wdReachRules.key | 0 .../rules/{ => wellDefined}/wdRegExRules.key | 0 .../rules/{ => wellDefined}/wdSeqRules.key | 0 .../rules/{ => wellDefined}/wdStringRules.key | 0 .../de/uka/ilkd/key/parser/TestParser.java | 3 ++- 35 files changed, 30 insertions(+), 33 deletions(-) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => classicalLogic}/firstOrderRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => classicalLogic}/formulaNormalisationRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => classicalLogic}/propRule.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => float}/floatAssignment2UpdateRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => float}/floatHeader.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => float}/floatRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => float}/floatRulesAssumeStrictfp.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => float}/floatRulesCommon.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => float}/floatRulesVerifyNormal.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => locset}/locSets.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => locset}/locSetsRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => permission}/permission.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => permission}/permissionRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/charListHeader.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/charListRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/regExAxioms.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/regExHeader.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/regExLemma.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/regExLemmaProven.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => string}/regExTheory.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wd.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdFormulaRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdGeneralRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdHeader.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdHeapRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdLocSetRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdNumericalRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdReachRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdRegExRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdSeqRules.key (100%) rename key.core/src/main/resources/de/uka/ilkd/key/proof/rules/{ => wellDefined}/wdStringRules.key (100%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java index 09f21f24d2..f33f633dc2 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java @@ -43,33 +43,29 @@ public Void visitOne_include_statement(KeYParser.One_include_statementContext ct public Void visitOne_include(KeYParser.One_includeContext ctx) { String value = StringUtil.trim(ctx.getText(), "\"'"); try { - addInclude(value, ctx.relfile != null); + addInclude(value); } catch (MalformedURLException e) { throw new BuildingException(ctx, e); } return null; } - private void addInclude(String filename, boolean relativePath) throws MalformedURLException { + private void addInclude(String filename) throws MalformedURLException { RuleSource source; if (!filename.endsWith(".key")) { filename += ".key"; } - if (relativePath) { - filename = filename.replace('/', File.separatorChar); // Not required for Windows, but - // whatsoever - filename = filename.replace('\\', File.separatorChar); // Special handling for Linux - var path = base.resolve(filename).normalize(); - var uri = URI.create(path.toString()); - if (uri.getScheme() == null) { - uri = URI.create("file:///" + path); - } - URL url = uri.toURL(); - source = RuleSourceFactory.initRuleFile(url); - } else { - source = RuleSourceFactory.fromDefaultLocation(filename); + filename = filename.replace('/', File.separatorChar); // Not required for Windows, but + // whatsoever + filename = filename.replace('\\', File.separatorChar); // Special handling for Linux + var path = base.resolve(filename).normalize(); + var uri = URI.create(path.toString()); + if (uri.getScheme() == null) { + uri = URI.create("file:///" + path); } + URL url = uri.toURL(); + source = RuleSourceFactory.initRuleFile(url); if (ldt) { includes.putLDT(filename, source); } else { diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/firstOrderRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/classicalLogic/firstOrderRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/firstOrderRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/classicalLogic/firstOrderRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/formulaNormalisationRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/classicalLogic/formulaNormalisationRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/formulaNormalisationRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/classicalLogic/formulaNormalisationRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/propRule.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/classicalLogic/propRule.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/propRule.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/classicalLogic/propRule.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatAssignment2UpdateRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatAssignment2UpdateRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatAssignment2UpdateRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatAssignment2UpdateRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatHeader.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatHeader.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatHeader.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatHeader.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRulesAssumeStrictfp.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRulesAssumeStrictfp.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRulesAssumeStrictfp.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRulesAssumeStrictfp.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRulesCommon.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRulesCommon.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRulesCommon.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRulesCommon.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRulesVerifyNormal.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRulesVerifyNormal.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/floatRulesVerifyNormal.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/float/floatRulesVerifyNormal.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key index 2cff1b7667..74084fe287 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key @@ -19,14 +19,14 @@ "./integer/integerHeader", "./integer/javaIntegerHeader", javaHeader, - floatHeader, + "./float/floatHeader", heap, - locSets, - permission, + "./locset/locSets", + "./permission/permission", reach, "./sequence/seq", map, freeADT, wellfound, - charListHeader, + "./string/charListHeader", types; diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locSets.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locset/locSets.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locSets.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locset/locSets.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locSetsRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locset/locSetsRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locSetsRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/locset/locSetsRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permission.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permission/permission.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permission.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permission/permission.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permissionRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permission/permissionRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permissionRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/permission/permissionRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key index 34a20b6cb0..69e1598571 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key @@ -10,10 +10,10 @@ // without a good reason. // general propositional and first-order rules -\include propRule; -\include firstOrderRules; +\include "./classicalLogic/propRule"; +\include "./classicalLogic/firstOrderRules"; \include ifThenElseRules; -\include formulaNormalisationRules; +\include "./classicalLogic/formulaNormalisationRules"; \include updateRules; // integer rules @@ -29,10 +29,10 @@ \include "./integer/intPow"; // float rules -\include floatRulesCommon; -\include floatRules, - floatRulesVerifyNormal, - floatRulesAssumeStrictfp; +\include "./float/floatRulesCommon"; +\include "./float/floatRules", + "./float/floatRulesVerifyNormal", + "./float/floatRulesAssumeStrictfp"; // \include abs; @@ -40,9 +40,9 @@ \include genericRules; // must go before heap, seq \include booleanRules; \include epsilon; -\include locSetsRules; // must go before heap +\include "./locset/locSetsRules"; // must go before heap \include heapRules; -\include permissionRules; +\include "./permission/permissionRules"; \include reachRules; \include "./sequence/seqCoreRules", "./sequence/seqRules"; \include "./sequence/seqPerm"; @@ -55,7 +55,7 @@ \include instanceAllocation; \include java5; \include "./integer/integerAssignment2UpdateRules"; -\include floatAssignment2UpdateRules; +\include "./float/floatAssignment2UpdateRules"; \include "./integer/bigint"; \include adtProgramDecompositionRules; @@ -63,8 +63,8 @@ \include precRules; // rules for strings and regular expressions -\include charListRules; -\include regExTheory; // TODO: fix rules and uncomment +\include "./string/charListRules"; +\include "./string/regExTheory"; // rules for information flow verification \include "./sequence/seqEq"; @@ -74,7 +74,7 @@ \include mapSize; // rules for well-definedness -\include wd; +\include "./wellDefined/wd"; // rules for invariant handling \include loopInvariantRules; diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/charListHeader.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/charListHeader.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/charListHeader.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/charListHeader.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/charListRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/charListRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/charListRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/charListRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExAxioms.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExAxioms.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExAxioms.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExAxioms.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExHeader.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExHeader.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExHeader.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExHeader.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExLemma.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExLemma.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExLemma.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExLemma.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExLemmaProven.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExLemmaProven.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExLemmaProven.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExLemmaProven.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExTheory.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExTheory.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/regExTheory.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/string/regExTheory.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wd.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wd.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wd.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wd.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdFormulaRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdFormulaRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdFormulaRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdFormulaRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdGeneralRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdGeneralRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdGeneralRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdGeneralRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdHeader.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdHeader.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdHeader.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdHeader.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdHeapRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdHeapRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdHeapRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdHeapRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdLocSetRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdLocSetRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdLocSetRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdLocSetRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdNumericalRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdNumericalRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdNumericalRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdNumericalRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdReachRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdReachRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdReachRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdReachRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdRegExRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdRegExRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdRegExRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdRegExRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdSeqRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdSeqRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdSeqRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdSeqRules.key diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdStringRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdStringRules.key similarity index 100% rename from key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wdStringRules.key rename to key.core/src/main/resources/de/uka/ilkd/key/proof/rules/wellDefined/wdStringRules.key diff --git a/key.core/src/test/java/de/uka/ilkd/key/parser/TestParser.java b/key.core/src/test/java/de/uka/ilkd/key/parser/TestParser.java index 5bba4dd7fe..a863637be5 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/parser/TestParser.java +++ b/key.core/src/test/java/de/uka/ilkd/key/parser/TestParser.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.nio.file.Path; import de.uka.ilkd.key.control.DefaultUserInterfaceControl; import de.uka.ilkd.key.control.KeYEnvironment; @@ -48,7 +49,7 @@ public void testRelativeInclude() throws IOException { expected.put(include.toString(), RuleSourceFactory.initRuleFile(include.toURI().toURL())); final String keyFile = "\\include \"" + include.getPath() + "\";"; KeyAst.File file = ParsingFacade.parseFile(CharStreams.fromString(keyFile)); - Includes actual = file.getIncludes(new File(".").toURI().toURL()); + Includes actual = file.getIncludes(Path.of(".")); // `Includes` does not provide an `Object#equals()` redefinition for the // moment, at least compare the list of filenames From c0b1a6246a5f86128dbef6aac7713a95d280c05f Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 23 Oct 2025 15:05:08 +0200 Subject: [PATCH 40/62] Documentation --- .../java/de/uka/ilkd/key/strategy/FOLStrategy.java | 6 ++++++ .../de/uka/ilkd/key/strategy/IntegerStrategy.java | 7 ++++++- .../ilkd/key/strategy/IntegerStrategyFactory.java | 2 ++ .../java/de/uka/ilkd/key/strategy/JFOLStrategy.java | 6 ++++++ ...StrategyFactory.java => JFOLStrategyFactory.java} | 4 +++- .../de/uka/ilkd/key/strategy/JavaCardDLStrategy.java | 8 +++++--- .../ilkd/key/strategy/JavaCardDLStrategyFactory.java | 8 +++----- .../uka/ilkd/key/strategy/ModularJavaDLStrategy.java | 10 ++++++++++ .../key/strategy/ModularJavaDLStrategyFactory.java | 12 +++++------- .../de/uka/ilkd/key/strategy/StringStrategy.java | 3 +++ .../uka/ilkd/key/strategy/StringStrategyFactory.java | 1 + .../java/de/uka/ilkd/key/strategy/SymExStrategy.java | 4 +++- .../uka/ilkd/key/strategy/SymExStrategyFactory.java | 1 + 13 files changed, 54 insertions(+), 18 deletions(-) rename key.core/src/main/java/de/uka/ilkd/key/strategy/{FOLStrategyFactory.java => JFOLStrategyFactory.java} (95%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index d625d8a2f7..580279d713 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -35,6 +35,12 @@ import org.jspecify.annotations.NonNull; +/// Strategy for general FOL rules. This does not consider other +/// theories like integers or Java-specific functions. +/// +/// In particular, instantiation of quantifiers is not supported by this +/// strategy, as the current E-matching depends on the theory of integers. +/// For that reason, instantiation can be found [JFOLStrategy]. public class FOLStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("FOL Strategy"); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 352b9aa7f4..89c18e022b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -35,7 +35,12 @@ import org.jspecify.annotations.NonNull; - +/// This strategy implements reasoning for integer arithmetics. In particular, +/// it supports linear integer arithmetics via Gaussian elimination, +/// Fourier-Motzkin; and non-linear integer reasoning via cross-multiplication +/// and Gröbner basis. +/// +/// Do not create directly, instead use [IntegerStrategyFactory]. public class IntegerStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("Integer Strategy"); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java index e9645d5422..c64563a9c9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java @@ -10,6 +10,8 @@ import org.key_project.logic.Name; +/// Factory for [IntegerStrategy]. Additionally, handles all strategy settings +/// relevant to integers. public class IntegerStrategyFactory implements StrategyFactory { public static final String TOOL_TIP_ARITHMETIC_BASE = "" + "Basic arithmetic support:" + "
    " + "
  • Simplification of polynomial expressions
  • " diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java index 4d4d1fbbd9..a26f2319d0 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java @@ -14,6 +14,12 @@ import org.key_project.prover.strategy.costbased.feature.SumFeature; import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; +/// This strategy extends the classical [FOLStrategy] with heuristics +/// for quantifier instantiation based on E-matching, which involves +/// normalization of quantified formulas, as well as term features depending on +/// integer theory. +/// +/// Do not create directly; use [JFOLStrategyFactory] instead. public class JFOLStrategy extends FOLStrategy { public JFOLStrategy(Proof proof, StrategyProperties strategyProperties) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java similarity index 95% rename from key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java rename to key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java index 5487117dd5..888b996268 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java @@ -13,7 +13,9 @@ import org.jspecify.annotations.NonNull; -public class FOLStrategyFactory implements StrategyFactory { +/// Factory for [JFOLStrategy]. Additionally, handles all strategy settings +/// relevant to it. +public class JFOLStrategyFactory implements StrategyFactory { public static final String TOOL_TIP_QUANTIFIER_NONE = "" + "Do not instantiate quantified formulas automatically" + ""; public static final String TOOL_TIP_QUANTIFIER_NO_SPLITS = "" diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 3bba99f2a9..39ee97b18a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -30,9 +30,11 @@ import org.jspecify.annotations.NonNull; -/** - * Strategy tailored to be used as long as a java program can be found in the sequent. - */ +/// This strategy is the catch-all for Java related features that are either +/// cross-cutting or one of the features that do not fit well into any other +/// strategy. +/// +/// Do not create directly, instead use [JavaCardDLStrategyFactory]. public class JavaCardDLStrategy extends AbstractFeatureStrategy { public static final AtomicLong PERF_COMPUTE = new AtomicLong(); public static final AtomicLong PERF_APPROVE = new AtomicLong(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index 9ae543f686..873eb4757b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java @@ -13,11 +13,9 @@ import org.key_project.logic.Name; - -/** - * - * @author Kai Wallisch - */ +/// Factory for [JavaCardDLStrategy]. Additionally, handles all strategy settings +/// relevant to it. +/// @author Kai Wallisch public class JavaCardDLStrategyFactory implements StrategyFactory { /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 715512a148..6b863ba708 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -31,6 +31,16 @@ import org.jspecify.annotations.NonNull; +/// Combines a list of strategies into a unified strategy. Theory combination +/// is based on the costs computed by each component strategy. Age of the rule +/// application is used to ensure that any applicable rule will eventually be +/// applied. +/// +/// Conflicts (i.e., when more than one component strategy provides a cost +/// computation for one rule set) have to be resolved explicitly by declaring +/// a conflict resolution [#resolveConflict(RuleSetDispatchFeature, RuleSet, List)]. +/// +/// Do not create directly. Use [ModularJavaDLStrategyFactory] instead. public class ModularJavaDLStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("Modular JavaDL Strategy"); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java index 132560da43..8ca24a854d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -20,14 +20,12 @@ import org.jspecify.annotations.NonNull; -/** - * - * @author Kai Wallisch - */ +/// Creates a [ModularJavaDLStrategy] and handles strategy settings relevant to it. public class ModularJavaDLStrategyFactory implements StrategyFactory { - private final List componentFactories = Arrays.asList(new FOLStrategyFactory(), - new IntegerStrategyFactory(), new SymExStrategyFactory(), new StringStrategyFactory(), - new JavaCardDLStrategyFactory()); + private final List componentFactories = + Arrays.asList(new JFOLStrategyFactory(), + new IntegerStrategyFactory(), new SymExStrategyFactory(), new StringStrategyFactory(), + new JavaCardDLStrategyFactory()); /** * The unique {@link Name} of this {@link StrategyFactory}. diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index bf212d867b..91bcef56ff 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -27,6 +27,9 @@ import org.jspecify.annotations.NonNull; +/// Strategy for string related rules. +/// +/// Do not create directly; use [StringStrategyFactory] instead. public class StringStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("String Strategy"); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java index 0756a89643..9d1a4b6813 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java @@ -8,6 +8,7 @@ import org.key_project.logic.Name; +/// Creates [StringStrategy]. public class StringStrategyFactory implements StrategyFactory { @Override public StringStrategy create(Proof proof, StrategyProperties strategyProperties) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index 778b44b545..5b12a316c1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -24,7 +24,9 @@ import org.jspecify.annotations.NonNull; -/// Strategy for symbolic execution rules +/// Strategy for symbolic execution rules. +/// +/// Do not create directly. Use [SymExStrategyFactory] instead. public class SymExStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("SymExStrategy"); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java index 51d6ebc3b8..7e7ab19dab 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java @@ -10,6 +10,7 @@ import org.key_project.logic.Name; +/// Creates [SymExStrategy]. Handles strategy settings for symbolic execution. public class SymExStrategyFactory implements StrategyFactory { public static final String TOOL_TIP_LOOP_INVARIANT = "" + "Use loop invariants for loops.
    " + "Three properties have to be shown:
    " From c32da1ef3254e0b1f7c679f621cb4d95c3f07a46 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 30 Oct 2025 15:16:25 +0100 Subject: [PATCH 41/62] Add proof settings to float files; use correct strategy factory for macros --- .../util/SymbolicExecutionUtil.java | 3 +- .../SelfcompositionStateExpansionMacro.java | 11 +-- .../de/uka/ilkd/key/strategy/FOLStrategy.java | 6 +- .../redux/arrays/Arrays.copyOf.float.key | 74 +++++++++++++++++++ .../redux/arrays/Arrays.copyOfRange.float.key | 74 +++++++++++++++++++ .../redux/arrays/Arrays.fill.float.key | 74 +++++++++++++++++++ .../redux/arrays/Arrays.fillFromTo.float.key | 74 +++++++++++++++++++ 7 files changed, 305 insertions(+), 11 deletions(-) diff --git a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java index a688d5aa65..07cab768c7 100644 --- a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java +++ b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java @@ -47,6 +47,7 @@ import de.uka.ilkd.key.speclang.Contract; import de.uka.ilkd.key.speclang.OperationContract; import de.uka.ilkd.key.strategy.JavaCardDLStrategyFactory; +import de.uka.ilkd.key.strategy.ModularJavaDLStrategyFactory; import de.uka.ilkd.key.strategy.Strategy; import de.uka.ilkd.key.strategy.StrategyProperties; import de.uka.ilkd.key.symbolic_execution.ExecutionVariableExtractor; @@ -4325,7 +4326,7 @@ public static void initializeStrategy(SymbolicExecutionTreeBuilder builder) { new SymbolicExecutionStrategy.Factory().create(proof, strategyProperties)); } else { proof.setActiveStrategy( - new JavaCardDLStrategyFactory().create(proof, strategyProperties)); + new ModularJavaDLStrategyFactory().create(proof, strategyProperties)); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/informationflow/macros/SelfcompositionStateExpansionMacro.java b/key.core/src/main/java/de/uka/ilkd/key/informationflow/macros/SelfcompositionStateExpansionMacro.java index 0c0da931f7..3ba8e6f857 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/informationflow/macros/SelfcompositionStateExpansionMacro.java +++ b/key.core/src/main/java/de/uka/ilkd/key/informationflow/macros/SelfcompositionStateExpansionMacro.java @@ -12,10 +12,7 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.proof.init.ProofOblInput; -import de.uka.ilkd.key.strategy.JavaCardDLStrategyFactory; -import de.uka.ilkd.key.strategy.RuleAppCostCollector; -import de.uka.ilkd.key.strategy.Strategy; -import de.uka.ilkd.key.strategy.StrategyProperties; +import de.uka.ilkd.key.strategy.*; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -136,10 +133,10 @@ public Name name() { String name = ruleApp.rule().name().toString(); if ((admittedRuleNames.contains(name) || name.startsWith(INF_FLOW_UNFOLD_PREFIX)) && ruleApplicationInContextAllowed(ruleApp, pio, goal)) { - JavaCardDLStrategyFactory strategyFactory = new JavaCardDLStrategyFactory(); - Strategy<@NonNull Goal> javaDlStrategy = + ModularJavaDLStrategyFactory strategyFactory = new ModularJavaDLStrategyFactory(); + Strategy<@NonNull Goal> dlStrategy = strategyFactory.create(goal.proof(), new StrategyProperties()); - RuleAppCost costs = javaDlStrategy.computeCost(ruleApp, pio, goal, mState); + RuleAppCost costs = dlStrategy.computeCost(ruleApp, pio, goal, mState); if ("orLeft".equals(name)) { costs = costs.add(NumberRuleAppCost.create(100)); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index 580279d713..d9da436db6 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -77,7 +77,7 @@ private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); bindRuleSet(d, "closure", -15000); - bindRuleSet(d, "alpha", -7000); + bindRuleSet(d, "alpha", print("alpha", longConst(-7000))); bindRuleSet(d, "delta", -6000); bindRuleSet(d, "simplify_boolean", -200); @@ -85,8 +85,8 @@ private RuleSetDispatchFeature setupCostComputationF() { FindDepthFeature.getInstance(); bindRuleSet(d, "concrete", - add(longConst(-11000), - ScaleFeature.createScaled(findDepthFeature, 10.0))); + print("Concrete", add(longConst(-11000), + ScaleFeature.createScaled(findDepthFeature, 10.0)))); bindRuleSet(d, "simplify", -4500); bindRuleSet(d, "simplify_enlarging", -2000); bindRuleSet(d, "simplify_ENLARGING", -1900); diff --git a/key.ui/examples/redux/arrays/Arrays.copyOf.float.key b/key.ui/examples/redux/arrays/Arrays.copyOf.float.key index 71d0ba1702..9c3968be39 100644 --- a/key.ui/examples/redux/arrays/Arrays.copyOf.float.key +++ b/key.ui/examples/redux/arrays/Arrays.copyOf.float.key @@ -1,3 +1,77 @@ +\settings // Proof-Settings-Config-File +{ + "Choice" : { + "JavaCard" : "JavaCard:off", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "floatRules" : "floatRules:strictfpOnly", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "methodExpansion" : "methodExpansion:modularOnly", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:allow", + "sequences" : "sequences:on", + "soundDefaultContracts" : "soundDefaultContracts:on", + "wdChecks" : "wdChecks:off", + "wdOperator" : "wdOperator:L" + }, + "Labels" : { + "UseOriginLabels" : true + }, + "NewSMT" : { + + }, + "SMTSettings" : { + "SelectedTaclets" : [ + + ], + "UseBuiltUniqueness" : false, + "explicitTypeHierarchy" : false, + "instantiateHierarchyAssumptions" : true, + "integersMaximum" : 2147483645, + "integersMinimum" : -2147483645, + "invariantForall" : false, + "maxGenericSorts" : 2, + "useConstantsForBigOrSmallIntegers" : true, + "useUninterpretedMultiplication" : true + }, + "Strategy" : { + "ActiveStrategy" : "Modular JavaDL Strategy", + "MaximumNumberOfAutomaticApplications" : 10000, + "Timeout" : -1, + "options" : { + "AUTO_INDUCTION_OPTIONS_KEY" : "AUTO_INDUCTION_OFF", + "BLOCK_OPTIONS_KEY" : "BLOCK_CONTRACT_INTERNAL", + "CLASS_AXIOM_OPTIONS_KEY" : "CLASS_AXIOM_FREE", + "DEP_OPTIONS_KEY" : "DEP_ON", + "INF_FLOW_CHECK_PROPERTY" : "INF_FLOW_CHECK_FALSE", + "LOOP_OPTIONS_KEY" : "LOOP_SCOPE_INV_TACLET", + "METHOD_OPTIONS_KEY" : "METHOD_CONTRACT", + "MPS_OPTIONS_KEY" : "MPS_MERGE", + "NON_LIN_ARITH_OPTIONS_KEY" : "NON_LIN_ARITH_NONE", + "OSS_OPTIONS_KEY" : "OSS_ON", + "QUANTIFIERS_OPTIONS_KEY" : "QUANTIFIERS_NON_SPLITTING_WITH_PROGS", + "QUERYAXIOM_OPTIONS_KEY" : "QUERYAXIOM_OFF", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", + "VBT_PHASE" : "VBT_SYM_EX" + } + } + } + \javaSource "./src"; \chooseContract "Arrays[Arrays::copyOf([F,int)].JML normal_behavior operation contract.0"; diff --git a/key.ui/examples/redux/arrays/Arrays.copyOfRange.float.key b/key.ui/examples/redux/arrays/Arrays.copyOfRange.float.key index 85111ad87f..371efe3289 100644 --- a/key.ui/examples/redux/arrays/Arrays.copyOfRange.float.key +++ b/key.ui/examples/redux/arrays/Arrays.copyOfRange.float.key @@ -1,3 +1,77 @@ +\settings // Proof-Settings-Config-File +{ + "Choice" : { + "JavaCard" : "JavaCard:off", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "floatRules" : "floatRules:strictfpOnly", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "methodExpansion" : "methodExpansion:modularOnly", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:allow", + "sequences" : "sequences:on", + "soundDefaultContracts" : "soundDefaultContracts:on", + "wdChecks" : "wdChecks:off", + "wdOperator" : "wdOperator:L" + }, + "Labels" : { + "UseOriginLabels" : true + }, + "NewSMT" : { + + }, + "SMTSettings" : { + "SelectedTaclets" : [ + + ], + "UseBuiltUniqueness" : false, + "explicitTypeHierarchy" : false, + "instantiateHierarchyAssumptions" : true, + "integersMaximum" : 2147483645, + "integersMinimum" : -2147483645, + "invariantForall" : false, + "maxGenericSorts" : 2, + "useConstantsForBigOrSmallIntegers" : true, + "useUninterpretedMultiplication" : true + }, + "Strategy" : { + "ActiveStrategy" : "Modular JavaDL Strategy", + "MaximumNumberOfAutomaticApplications" : 10000, + "Timeout" : -1, + "options" : { + "AUTO_INDUCTION_OPTIONS_KEY" : "AUTO_INDUCTION_OFF", + "BLOCK_OPTIONS_KEY" : "BLOCK_CONTRACT_INTERNAL", + "CLASS_AXIOM_OPTIONS_KEY" : "CLASS_AXIOM_FREE", + "DEP_OPTIONS_KEY" : "DEP_ON", + "INF_FLOW_CHECK_PROPERTY" : "INF_FLOW_CHECK_FALSE", + "LOOP_OPTIONS_KEY" : "LOOP_SCOPE_INV_TACLET", + "METHOD_OPTIONS_KEY" : "METHOD_CONTRACT", + "MPS_OPTIONS_KEY" : "MPS_MERGE", + "NON_LIN_ARITH_OPTIONS_KEY" : "NON_LIN_ARITH_NONE", + "OSS_OPTIONS_KEY" : "OSS_ON", + "QUANTIFIERS_OPTIONS_KEY" : "QUANTIFIERS_NON_SPLITTING_WITH_PROGS", + "QUERYAXIOM_OPTIONS_KEY" : "QUERYAXIOM_OFF", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", + "VBT_PHASE" : "VBT_SYM_EX" + } + } + } + \javaSource "./src"; \chooseContract "Arrays[Arrays::copyOfRange([F,int,int)].JML normal_behavior operation contract.0"; diff --git a/key.ui/examples/redux/arrays/Arrays.fill.float.key b/key.ui/examples/redux/arrays/Arrays.fill.float.key index eb36cfd220..bb60623d33 100644 --- a/key.ui/examples/redux/arrays/Arrays.fill.float.key +++ b/key.ui/examples/redux/arrays/Arrays.fill.float.key @@ -1,3 +1,77 @@ +\settings // Proof-Settings-Config-File +{ + "Choice" : { + "JavaCard" : "JavaCard:off", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "floatRules" : "floatRules:strictfpOnly", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "methodExpansion" : "methodExpansion:modularOnly", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:allow", + "sequences" : "sequences:on", + "soundDefaultContracts" : "soundDefaultContracts:on", + "wdChecks" : "wdChecks:off", + "wdOperator" : "wdOperator:L" + }, + "Labels" : { + "UseOriginLabels" : true + }, + "NewSMT" : { + + }, + "SMTSettings" : { + "SelectedTaclets" : [ + + ], + "UseBuiltUniqueness" : false, + "explicitTypeHierarchy" : false, + "instantiateHierarchyAssumptions" : true, + "integersMaximum" : 2147483645, + "integersMinimum" : -2147483645, + "invariantForall" : false, + "maxGenericSorts" : 2, + "useConstantsForBigOrSmallIntegers" : true, + "useUninterpretedMultiplication" : true + }, + "Strategy" : { + "ActiveStrategy" : "Modular JavaDL Strategy", + "MaximumNumberOfAutomaticApplications" : 10000, + "Timeout" : -1, + "options" : { + "AUTO_INDUCTION_OPTIONS_KEY" : "AUTO_INDUCTION_OFF", + "BLOCK_OPTIONS_KEY" : "BLOCK_CONTRACT_INTERNAL", + "CLASS_AXIOM_OPTIONS_KEY" : "CLASS_AXIOM_FREE", + "DEP_OPTIONS_KEY" : "DEP_ON", + "INF_FLOW_CHECK_PROPERTY" : "INF_FLOW_CHECK_FALSE", + "LOOP_OPTIONS_KEY" : "LOOP_SCOPE_INV_TACLET", + "METHOD_OPTIONS_KEY" : "METHOD_CONTRACT", + "MPS_OPTIONS_KEY" : "MPS_MERGE", + "NON_LIN_ARITH_OPTIONS_KEY" : "NON_LIN_ARITH_NONE", + "OSS_OPTIONS_KEY" : "OSS_ON", + "QUANTIFIERS_OPTIONS_KEY" : "QUANTIFIERS_NON_SPLITTING_WITH_PROGS", + "QUERYAXIOM_OPTIONS_KEY" : "QUERYAXIOM_OFF", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", + "VBT_PHASE" : "VBT_SYM_EX" + } + } + } + \javaSource "./src"; \chooseContract "Arrays[Arrays::fill([F,float)].JML normal_behavior operation contract.0"; \ No newline at end of file diff --git a/key.ui/examples/redux/arrays/Arrays.fillFromTo.float.key b/key.ui/examples/redux/arrays/Arrays.fillFromTo.float.key index 3d50ab9ea6..5e5ef65967 100644 --- a/key.ui/examples/redux/arrays/Arrays.fillFromTo.float.key +++ b/key.ui/examples/redux/arrays/Arrays.fillFromTo.float.key @@ -1,3 +1,77 @@ +\settings // Proof-Settings-Config-File +{ + "Choice" : { + "JavaCard" : "JavaCard:off", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "floatRules" : "floatRules:strictfpOnly", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "methodExpansion" : "methodExpansion:modularOnly", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:allow", + "sequences" : "sequences:on", + "soundDefaultContracts" : "soundDefaultContracts:on", + "wdChecks" : "wdChecks:off", + "wdOperator" : "wdOperator:L" + }, + "Labels" : { + "UseOriginLabels" : true + }, + "NewSMT" : { + + }, + "SMTSettings" : { + "SelectedTaclets" : [ + + ], + "UseBuiltUniqueness" : false, + "explicitTypeHierarchy" : false, + "instantiateHierarchyAssumptions" : true, + "integersMaximum" : 2147483645, + "integersMinimum" : -2147483645, + "invariantForall" : false, + "maxGenericSorts" : 2, + "useConstantsForBigOrSmallIntegers" : true, + "useUninterpretedMultiplication" : true + }, + "Strategy" : { + "ActiveStrategy" : "Modular JavaDL Strategy", + "MaximumNumberOfAutomaticApplications" : 10000, + "Timeout" : -1, + "options" : { + "AUTO_INDUCTION_OPTIONS_KEY" : "AUTO_INDUCTION_OFF", + "BLOCK_OPTIONS_KEY" : "BLOCK_CONTRACT_INTERNAL", + "CLASS_AXIOM_OPTIONS_KEY" : "CLASS_AXIOM_FREE", + "DEP_OPTIONS_KEY" : "DEP_ON", + "INF_FLOW_CHECK_PROPERTY" : "INF_FLOW_CHECK_FALSE", + "LOOP_OPTIONS_KEY" : "LOOP_SCOPE_INV_TACLET", + "METHOD_OPTIONS_KEY" : "METHOD_CONTRACT", + "MPS_OPTIONS_KEY" : "MPS_MERGE", + "NON_LIN_ARITH_OPTIONS_KEY" : "NON_LIN_ARITH_NONE", + "OSS_OPTIONS_KEY" : "OSS_ON", + "QUANTIFIERS_OPTIONS_KEY" : "QUANTIFIERS_NON_SPLITTING_WITH_PROGS", + "QUERYAXIOM_OPTIONS_KEY" : "QUERYAXIOM_OFF", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", + "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", + "VBT_PHASE" : "VBT_SYM_EX" + } + } + } + \javaSource "./src"; \chooseContract "Arrays[Arrays::fill([F,int,int,float)].JML normal_behavior operation contract.0"; \ No newline at end of file From 700f0efb55a9f3408723ef9cd29c023115cf990d Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 30 Oct 2025 15:31:44 +0100 Subject: [PATCH 42/62] Remove printing --- .../src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index d9da436db6..580279d713 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -77,7 +77,7 @@ private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); bindRuleSet(d, "closure", -15000); - bindRuleSet(d, "alpha", print("alpha", longConst(-7000))); + bindRuleSet(d, "alpha", -7000); bindRuleSet(d, "delta", -6000); bindRuleSet(d, "simplify_boolean", -200); @@ -85,8 +85,8 @@ private RuleSetDispatchFeature setupCostComputationF() { FindDepthFeature.getInstance(); bindRuleSet(d, "concrete", - print("Concrete", add(longConst(-11000), - ScaleFeature.createScaled(findDepthFeature, 10.0)))); + add(longConst(-11000), + ScaleFeature.createScaled(findDepthFeature, 10.0))); bindRuleSet(d, "simplify", -4500); bindRuleSet(d, "simplify_enlarging", -2000); bindRuleSet(d, "simplify_ENLARGING", -1900); From ba7fde66d66682376bb1218b5038ebc12916075b Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 30 Oct 2025 15:33:43 +0100 Subject: [PATCH 43/62] Spotless --- .../ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java | 1 - 1 file changed, 1 deletion(-) diff --git a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java index 07cab768c7..724ce2bbe1 100644 --- a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java +++ b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/util/SymbolicExecutionUtil.java @@ -46,7 +46,6 @@ import de.uka.ilkd.key.settings.StrategySettings; import de.uka.ilkd.key.speclang.Contract; import de.uka.ilkd.key.speclang.OperationContract; -import de.uka.ilkd.key.strategy.JavaCardDLStrategyFactory; import de.uka.ilkd.key.strategy.ModularJavaDLStrategyFactory; import de.uka.ilkd.key.strategy.Strategy; import de.uka.ilkd.key.strategy.StrategyProperties; From 3e81c70fefe38cb652d7d0607366380ac195676e Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 6 Nov 2025 14:10:57 +0100 Subject: [PATCH 44/62] Add .key file ending to relative paths --- .../de/uka/ilkd/key/proof/rules/ldt.key | 14 ++--- .../ilkd/key/proof/rules/standardRules.key | 58 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key index 74084fe287..e5d9b942cc 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key @@ -16,17 +16,17 @@ ruleSetsDeclarations, soundDefaultContracts, boolean, - "./integer/integerHeader", - "./integer/javaIntegerHeader", + "./integer/integerHeader.key", + "./integer/javaIntegerHeader.key", javaHeader, - "./float/floatHeader", + "./float/floatHeader.key", heap, - "./locset/locSets", - "./permission/permission", + "./locset/locSets.key", + "./permission/permission.key", reach, - "./sequence/seq", + "./sequence/seq.key", map, freeADT, wellfound, - "./string/charListHeader", + "./string/charListHeader.key", types; diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key index 69e1598571..f5a06be72b 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/standardRules.key @@ -10,29 +10,29 @@ // without a good reason. // general propositional and first-order rules -\include "./classicalLogic/propRule"; -\include "./classicalLogic/firstOrderRules"; +\include "./classicalLogic/propRule.key"; +\include "./classicalLogic/firstOrderRules.key"; \include ifThenElseRules; -\include "./classicalLogic/formulaNormalisationRules"; +\include "./classicalLogic/formulaNormalisationRules.key"; \include updateRules; // integer rules -\include "./integer/integerRulesCommon"; -\include "./integer/intRules", - "./integer/intRulesUncheckedSemantics", - "./integer/intRulesCheckedSemantics", - "./integer/intRulesJavaSemantics"; -\include "./integer/integerSimplificationRules"; -\include "./integer/intDiv"; -\include "./integer/bsum", "./integer/bprod"; -\include "./integer/binaryAxioms", "./integer/binaryLemmas"; -\include "./integer/intPow"; +\include "./integer/integerRulesCommon.key"; +\include "./integer/intRules.key", + "./integer/intRulesUncheckedSemantics.key", + "./integer/intRulesCheckedSemantics.key", + "./integer/intRulesJavaSemantics.key"; +\include "./integer/integerSimplificationRules.key"; +\include "./integer/intDiv.key"; +\include "./integer/bsum.key", "./integer/bprod.key"; +\include "./integer/binaryAxioms.key", "./integer/binaryLemmas.key"; +\include "./integer/intPow.key"; // float rules -\include "./float/floatRulesCommon"; -\include "./float/floatRules", - "./float/floatRulesVerifyNormal", - "./float/floatRulesAssumeStrictfp"; +\include "./float/floatRulesCommon.key"; +\include "./float/floatRules.key", + "./float/floatRulesVerifyNormal.key", + "./float/floatRulesAssumeStrictfp.key"; // \include abs; @@ -40,13 +40,13 @@ \include genericRules; // must go before heap, seq \include booleanRules; \include epsilon; -\include "./locset/locSetsRules"; // must go before heap +\include "./locset/locSetsRules.key"; // must go before heap \include heapRules; -\include "./permission/permissionRules"; +\include "./permission/permissionRules.key"; \include reachRules; -\include "./sequence/seqCoreRules", "./sequence/seqRules"; -\include "./sequence/seqPerm"; -\include "./sequence/seqPerm2"; +\include "./sequence/seqCoreRules.key", "./sequence/seqRules.key"; +\include "./sequence/seqPerm.key"; +\include "./sequence/seqPerm2.key"; // rules for Java (order does not matter, since not provable anyway) \include javaRules; @@ -54,27 +54,27 @@ \include activeUse; \include instanceAllocation; \include java5; -\include "./integer/integerAssignment2UpdateRules"; -\include "./float/floatAssignment2UpdateRules"; -\include "./integer/bigint"; +\include "./integer/integerAssignment2UpdateRules.key"; +\include "./float/floatAssignment2UpdateRules.key"; +\include "./integer/bigint.key"; \include adtProgramDecompositionRules; // wellfounded relation \include precRules; // rules for strings and regular expressions -\include "./string/charListRules"; -\include "./string/regExTheory"; +\include "./string/charListRules.key"; +\include "./string/regExTheory.key"; // rules for information flow verification -\include "./sequence/seqEq"; +\include "./sequence/seqEq.key"; \include infFlow; // size rules for maps \include mapSize; // rules for well-definedness -\include "./wellDefined/wd"; +\include "./wellDefined/wd.key"; // rules for invariant handling \include loopInvariantRules; From 1d1c22847646c50fb28c85ba4c474ddae1a6796c Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 6 Nov 2025 15:26:32 +0100 Subject: [PATCH 45/62] Slight performance improvement --- .../AbstractPropositionalExpansionMacro.java | 2 - ...repareInfFlowContractPreBranchesMacro.java | 13 --- .../key/strategy/AbstractFeatureStrategy.java | 5 -- .../ilkd/key/strategy/ComponentStrategy.java | 17 ++++ .../de/uka/ilkd/key/strategy/FOLStrategy.java | 18 +++- .../ilkd/key/strategy/IntegerStrategy.java | 17 +++- .../ilkd/key/strategy/JavaCardDLStrategy.java | 17 +++- .../key/strategy/ModularJavaDLStrategy.java | 85 ++++++++++--------- .../ModularJavaDLStrategyFactory.java | 4 +- .../de/uka/ilkd/key/strategy/Strategy.java | 7 ++ .../uka/ilkd/key/strategy/StringStrategy.java | 14 ++- .../uka/ilkd/key/strategy/SymExStrategy.java | 17 +++- .../feature/RuleSetDispatchFeature.java | 3 +- 13 files changed, 142 insertions(+), 77 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/AbstractPropositionalExpansionMacro.java b/key.core/src/main/java/de/uka/ilkd/key/macros/AbstractPropositionalExpansionMacro.java index 3730ae239d..90bd501af1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/AbstractPropositionalExpansionMacro.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/AbstractPropositionalExpansionMacro.java @@ -86,7 +86,6 @@ protected boolean ruleApplicationInContextAllowed(RuleApp ruleApp, * rejects everything else. */ private static class PropExpansionStrategy implements Strategy { - private final Name NAME = new Name(PropExpansionStrategy.class.getSimpleName()); private final Set admittedRuleNames; @@ -142,6 +141,5 @@ public void instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, public boolean isStopAtFirstNonCloseableGoal() { return false; } - } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java b/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java index fefab75a73..57d8045383 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/PrepareInfFlowContractPreBranchesMacro.java @@ -10,7 +10,6 @@ import de.uka.ilkd.key.strategy.AbstractFeatureStrategy; import de.uka.ilkd.key.strategy.Strategy; import de.uka.ilkd.key.strategy.feature.FocusIsSubFormulaOfInfFlowContractAppFeature; -import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -138,21 +137,9 @@ private String getAppRuleName(Node parent) { return parentRuleName; } - - @Override - protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, - MutableState mState) { - return computeCost(app, pio, goal, mState); - } - @Override public boolean isStopAtFirstNonCloseableGoal() { return false; } - - @Override - protected RuleSetDispatchFeature getCostDispatcher() { - return new RuleSetDispatchFeature(); - } } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java index 31f1d8a753..0da5822605 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/AbstractFeatureStrategy.java @@ -150,9 +150,6 @@ protected final Feature isBelow(TermFeature t) { not(applyTF(superTerm, t)))); } - protected abstract RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, - MutableState mState); - protected Feature forEach(TermBuffer x, TermGenerator gen, Feature body) { return ForEachCP.create(x, gen, body); } @@ -202,6 +199,4 @@ protected Feature instantiateTriggeredVariable(ProjectionToTerm value) { protected Feature instantiate(String sv, ProjectionToTerm value) { return instantiate(new Name(sv), value); } - - protected abstract RuleSetDispatchFeature getCostDispatcher(); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java new file mode 100644 index 0000000000..f3a3f26bb1 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java @@ -0,0 +1,17 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import java.util.Set; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; + +import org.key_project.prover.rules.RuleSet; + +public interface ComponentStrategy extends Strategy { + RuleSetDispatchFeature getCostDispatcher(); + + Set getResponsibilities(); +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index 580279d713..b3b6e56407 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -3,6 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; +import java.util.HashSet; +import java.util.Set; + import de.uka.ilkd.key.logic.op.Equality; import de.uka.ilkd.key.logic.op.Junctor; import de.uka.ilkd.key.logic.op.Quantifier; @@ -41,7 +44,7 @@ /// In particular, instantiation of quantifiers is not supported by this /// strategy, as the current E-matching depends on the theory of integers. /// For that reason, instantiation can be found [JFOLStrategy]. -public class FOLStrategy extends AbstractFeatureStrategy { +public class FOLStrategy extends AbstractFeatureStrategy implements ComponentStrategy { public static final Name NAME = new Name("FOL Strategy"); protected final StrategyProperties strategyProperties; @@ -187,13 +190,13 @@ private RuleSetDispatchFeature setupInstantiationF() { } @Override - protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { return instantiationF.computeCost(app, pio, goal, mState); } @Override - protected RuleSetDispatchFeature getCostDispatcher() { + public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } @@ -213,6 +216,15 @@ public boolean isResponsibleFor(RuleSet rs) { || approvalDispatcher.get(rs) != null; } + @Override + public Set getResponsibilities() { + var set = new HashSet(); + set.addAll(costComputationDispatcher.ruleSets()); + set.addAll(instantiationDispatcher.ruleSets()); + set.addAll(approvalDispatcher.ruleSets()); + return set; + } + @Override public Name name() { return NAME; diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 89c18e022b..742fbe4307 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -3,6 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; +import java.util.HashSet; +import java.util.Set; + import de.uka.ilkd.key.ldt.IntegerLDT; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.op.Equality; @@ -41,7 +44,7 @@ /// and Gröbner basis. /// /// Do not create directly, instead use [IntegerStrategyFactory]. -public class IntegerStrategy extends AbstractFeatureStrategy { +public class IntegerStrategy extends AbstractFeatureStrategy implements ComponentStrategy { public static final Name NAME = new Name("Integer Strategy"); @@ -93,6 +96,14 @@ public boolean isResponsibleFor(RuleSet rs) { return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; } + @Override + public Set getResponsibilities() { + var set = new HashSet(); + set.addAll(costComputationDispatcher.ruleSets()); + set.addAll(instantiationDispatcher.ruleSets()); + return set; + } + private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); @@ -997,7 +1008,7 @@ public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { } @Override - protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { return instantiationDispatcher.computeCost(app, pio, goal, mState); } @@ -1014,7 +1025,7 @@ public Name name() { } @Override - protected RuleSetDispatchFeature getCostDispatcher() { + public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 39ee97b18a..9c67239ecc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -3,6 +3,8 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import de.uka.ilkd.key.ldt.HeapLDT; @@ -35,7 +37,7 @@ /// strategy. /// /// Do not create directly, instead use [JavaCardDLStrategyFactory]. -public class JavaCardDLStrategy extends AbstractFeatureStrategy { +public class JavaCardDLStrategy extends AbstractFeatureStrategy implements ComponentStrategy { public static final AtomicLong PERF_COMPUTE = new AtomicLong(); public static final AtomicLong PERF_APPROVE = new AtomicLong(); public static final AtomicLong PERF_INSTANTIATE = new AtomicLong(); @@ -89,6 +91,15 @@ public boolean isResponsibleFor(RuleSet rs) { || approvalDispatcher.get(rs) != null; } + @Override + public Set getResponsibilities() { + var set = new HashSet(); + set.addAll(costComputationDispatcher.ruleSets()); + set.addAll(instantiationDispatcher.ruleSets()); + set.addAll(approvalDispatcher.ruleSets()); + return set; + } + protected Feature setupGlobalF(@NonNull Feature dispatcher) { final String queryProp = strategyProperties.getProperty(StrategyProperties.QUERY_OPTIONS_KEY); @@ -539,7 +550,7 @@ public final boolean isApprovedApp(RuleApp app, } @Override - protected RuleAppCost instantiateApp(RuleApp app, + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { var time = System.nanoTime(); @@ -565,7 +576,7 @@ public boolean isStopAtFirstNonCloseableGoal() { } @Override - protected RuleSetDispatchFeature getCostDispatcher() { + public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 6b863ba708..30978f09a2 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -3,9 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; @@ -19,6 +17,7 @@ import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.Rule; import org.key_project.prover.rules.RuleApp; import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; @@ -44,30 +43,42 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("Modular JavaDL Strategy"); - private final List strategies = new ArrayList<>(); + private final List strategies = new ArrayList<>(); private final StrategyProperties strategyProperties; private final Feature reduceCostTillMaxF; private final Feature reduceInstTillMaxF; private final ArithTermFeatures tf; private final RuleSetDispatchFeature conflictCostDispatcher; + private final Feature totalCost; + private final Map> responsibilityMap; + private final Map> ruleToStrategyMap = + new LinkedHashMap<>(); - public ModularJavaDLStrategy(Proof proof, List componentStrategies, + public ModularJavaDLStrategy(Proof proof, List componentStrategies, StrategyProperties properties) { super(proof); strategies.addAll(componentStrategies); reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost); - reduceInstTillMaxF = new ReduceTillMaxFeature(AbstractFeatureStrategy::instantiateApp); + reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); conflictCostDispatcher = resolveConflicts(); - } + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + totalCost = + add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, + reduceCostTillMaxF, conflictCostDispatcher, + AgeFeature.INSTANCE, ifMatchedF); - @Override - protected RuleSetDispatchFeature getCostDispatcher() { - return conflictCostDispatcher; + responsibilityMap = new LinkedHashMap<>(strategies.size()); + for (ComponentStrategy strategy : strategies) { + var res = strategy.getResponsibilities(); + for (var rs : res) { + responsibilityMap.computeIfAbsent(rs, k -> new ArrayList<>()).add(strategy); + } + } } - private record StratAndDispatcher(AbstractFeatureStrategy strategy, + private record StratAndDispatcher(ComponentStrategy strategy, RuleSetDispatchFeature dispatcher) { } @@ -75,7 +86,7 @@ private RuleSetDispatchFeature resolveConflicts() { var dis = new RuleSetDispatchFeature(); var dispatchers = strategies.stream().map(s -> new StratAndDispatcher(s, s.getCostDispatcher())).toList(); - var map = new HashMap>(); + var map = new HashMap>(); for (var d : dispatchers) { var s = d.strategy; for (var rs : d.dispatcher.ruleSets()) { @@ -92,7 +103,7 @@ private RuleSetDispatchFeature resolveConflicts() { } private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, - List value) { + List value) { switch (rs.name().toString()) { case "order_terms" -> { var folStrat = value.getFirst(); @@ -127,7 +138,7 @@ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, } @Override - protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { enableInstantiate(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); @@ -160,24 +171,10 @@ public Name name() { } private R reduceTillMax(RuleApp app, R init, R max, BiFunction accumulator, - Function mapper, Object... conflict) { - for (AbstractFeatureStrategy strategy : strategies) { - var isResponsible = false; - var ruleSets = app.rule().ruleSets(); - if (!ruleSets.hasNext()) - isResponsible = true; - else { - while (ruleSets.hasNext()) { - var rs = ruleSets.next(); - if (strategy.isResponsibleFor(rs)) { - isResponsible = true; - break; - } - } - } - if (!isResponsible) { - continue; - } + Function mapper) { + LinkedHashSet strats = getResponsibleStrategies(app); + + for (ComponentStrategy strategy : strats) { init = accumulator.apply(init, mapper.apply(strategy)); if (init == max) { break; @@ -186,21 +183,31 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu return init; } + private LinkedHashSet getResponsibleStrategies(RuleApp app) { + LinkedHashSet strats = ruleToStrategyMap.get(app.rule()); + if (strats == null) { + strats = new LinkedHashSet<>(); + var ruleSets = app.rule().ruleSets(); + while (ruleSets.hasNext()) { + var rs = ruleSets.next(); + List s = responsibilityMap.get(rs); + if (s != null) + strats.addAll(s); + } + ruleToStrategyMap.put(app.rule(), strats); + } + return strats; + } + @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { - final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); - // TODO: This could be inefficient. Maybe we can simplify conflict resolution - Feature totalCost = - add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, - reduceCostTillMaxF, conflictCostDispatcher, - AgeFeature.INSTANCE, ifMatchedF); return totalCost.computeCost(app, pos, goal, mState); } @FunctionalInterface private interface StrategyCostFunction { - RuleAppCost compute(AbstractFeatureStrategy strategy, RuleApp app, + RuleAppCost compute(ComponentStrategy strategy, RuleApp app, PosInOccurrence pos, Goal goal, MutableState mState); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java index 8ca24a854d..a356f1b00e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -123,8 +123,8 @@ private static OneOfStrategyPropertyDefinition getUserOptions() { @Override public Strategy<@NonNull Goal> create(Proof proof, StrategyProperties strategyProperties) { - List componentStrategies = componentFactories.stream() - .map(f -> (AbstractFeatureStrategy) f.create(proof, strategyProperties)) + List componentStrategies = componentFactories.stream() + .map(f -> (ComponentStrategy) f.create(proof, strategyProperties)) .collect(Collectors.toList()); return new ModularJavaDLStrategy(proof, componentStrategies, strategyProperties); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java index 06abc31c62..6d1c1fd190 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java @@ -19,6 +19,7 @@ import org.jspecify.annotations.NonNull; + /** * Generic interface for evaluating the cost of a RuleApp with regard to a specific strategy */ @@ -82,4 +83,10 @@ static void updateStrategySettings(Proof proof, StrategyProperties p) { } default boolean isResponsibleFor(RuleSet rs) { return false; } + + default RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, + de.uka.ilkd.key.proof.Goal goal, + MutableState mState) { + return null; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index 91bcef56ff..22d31ba7e1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -3,6 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; +import java.util.HashSet; +import java.util.Set; + import de.uka.ilkd.key.ldt.BooleanLDT; import de.uka.ilkd.key.ldt.CharListLDT; import de.uka.ilkd.key.ldt.SeqLDT; @@ -30,7 +33,7 @@ /// Strategy for string related rules. /// /// Do not create directly; use [StringStrategyFactory] instead. -public class StringStrategy extends AbstractFeatureStrategy { +public class StringStrategy extends AbstractFeatureStrategy implements ComponentStrategy { public static final Name NAME = new Name("String Strategy"); /// The features defining the three phases: cost computation, approval, @@ -60,6 +63,11 @@ public boolean isResponsibleFor(RuleSet rs) { return costComputationDispatcher.get(rs) != null; } + @Override + public Set getResponsibilities() { + return new HashSet<>(costComputationDispatcher.ruleSets()); + } + private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); setUpStringNormalisation(d); @@ -165,7 +173,7 @@ public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { } @Override - protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { return longConst(0).computeCost(app, pio, goal, mState); } @@ -182,7 +190,7 @@ public Name name() { } @Override - protected RuleSetDispatchFeature getCostDispatcher() { + public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index 5b12a316c1..5f17ddd51b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -3,6 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; +import java.util.HashSet; +import java.util.Set; + import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.strategy.feature.*; @@ -27,7 +30,7 @@ /// Strategy for symbolic execution rules. /// /// Do not create directly. Use [SymExStrategyFactory] instead. -public class SymExStrategy extends AbstractFeatureStrategy { +public class SymExStrategy extends AbstractFeatureStrategy implements ComponentStrategy { public static final Name NAME = new Name("SymExStrategy"); private final FormulaTermFeatures ff; @@ -58,6 +61,14 @@ public boolean isResponsibleFor(RuleSet rs) { return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; } + @Override + public Set getResponsibilities() { + var set = new HashSet(); + set.addAll(costComputationDispatcher.ruleSets()); + set.addAll(instantiationDispatcher.ruleSets()); + return set; + } + private Feature setupGlobalF(Feature dispatcher) { final Feature methodSpecF; final String methProp = @@ -215,7 +226,7 @@ private RuleSetDispatchFeature setupCostComputationF() { } @Override - protected RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { return instantiationF.computeCost(app, pio, goal, mState); } @@ -242,7 +253,7 @@ public Name name() { } @Override - protected RuleSetDispatchFeature getCostDispatcher() { + public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java index f51c116ae1..4b41c75ff2 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/RuleSetDispatchFeature.java @@ -5,6 +5,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; import de.uka.ilkd.key.rule.TacletApp; @@ -33,7 +34,7 @@ public class RuleSetDispatchFeature implements Feature { private final Map rulesetToFeature = new LinkedHashMap<>(); - public Iterable ruleSets() { + public Set ruleSets() { return rulesetToFeature.keySet(); } From 62f4da94c83e731632cabc4eb161ce63c524fd52 Mon Sep 17 00:00:00 2001 From: Drodt Date: Fri, 7 Nov 2025 09:52:51 +0100 Subject: [PATCH 46/62] Simplify --- .../uka/ilkd/key/strategy/ModularJavaDLStrategy.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 30978f09a2..271fba819b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -172,7 +172,7 @@ public Name name() { private R reduceTillMax(RuleApp app, R init, R max, BiFunction accumulator, Function mapper) { - LinkedHashSet strats = getResponsibleStrategies(app); + LinkedHashSet strats = getResponsibleStrategies(app.rule()); for (ComponentStrategy strategy : strats) { init = accumulator.apply(init, mapper.apply(strategy)); @@ -183,18 +183,18 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu return init; } - private LinkedHashSet getResponsibleStrategies(RuleApp app) { - LinkedHashSet strats = ruleToStrategyMap.get(app.rule()); + private LinkedHashSet getResponsibleStrategies(Rule rule) { + LinkedHashSet strats = ruleToStrategyMap.get(rule); if (strats == null) { strats = new LinkedHashSet<>(); - var ruleSets = app.rule().ruleSets(); + var ruleSets = rule.ruleSets(); while (ruleSets.hasNext()) { var rs = ruleSets.next(); List s = responsibilityMap.get(rs); if (s != null) strats.addAll(s); } - ruleToStrategyMap.put(app.rule(), strats); + ruleToStrategyMap.put(rule, strats); } return strats; } From cc0df1a05ef66b02a5e2b28b88045c7c019c2897 Mon Sep 17 00:00:00 2001 From: Drodt Date: Fri, 7 Nov 2025 10:34:19 +0100 Subject: [PATCH 47/62] Fix OSS --- .../uka/ilkd/key/rule/OneStepSimplifier.java | 1 - .../de/uka/ilkd/key/strategy/FOLStrategy.java | 18 ++++++- .../uka/ilkd/key/strategy/JFOLStrategy.java | 7 +++ .../ilkd/key/strategy/JavaCardDLStrategy.java | 4 -- .../key/strategy/ModularJavaDLStrategy.java | 51 +++++++++++-------- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java b/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java index 5f5d6cb498..5a6461e885 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java @@ -688,7 +688,6 @@ public Set getCapturedTaclets() { return result; } - // ------------------------------------------------------------------------- // inner classes // ------------------------------------------------------------------------- diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index b3b6e56407..e87c6a8795 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -21,9 +21,11 @@ import de.uka.ilkd.key.strategy.termgenerator.AllowedCutPositionsGenerator; import de.uka.ilkd.key.strategy.termgenerator.SuperTermGenerator; import de.uka.ilkd.key.strategy.termgenerator.TriggeredInstantiations; +import de.uka.ilkd.key.util.MiscTools; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.proof.rulefilter.SetRuleFilter; import org.key_project.prover.rules.RuleApp; import org.key_project.prover.rules.RuleSet; import org.key_project.prover.sequent.PosInOccurrence; @@ -71,11 +73,23 @@ public FOLStrategy(Proof proof, StrategyProperties strategyProperties) { approvalDispatcher = setupApprovalDispatcher(); instantiationDispatcher = setupInstantiationF(); - costComputationF = costComputationDispatcher; - instantiationF = instantiationDispatcher; + costComputationF = setUpGlobalF(costComputationDispatcher); + instantiationF = setUpGlobalF(instantiationDispatcher); approvalF = approvalDispatcher; } + private Feature setUpGlobalF(RuleSetDispatchFeature d) { + final Feature oneStepSimplificationF = + oneStepSimplificationFeature(longConst(-11000)); + return add(d, oneStepSimplificationF); + } + + private Feature oneStepSimplificationFeature(Feature cost) { + SetRuleFilter filter = new SetRuleFilter(); + filter.addRuleToSet(MiscTools.findOneStepSimplifier(getProof())); + return ConditionalFeature.createConditional(filter, cost); + } + private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java index a26f2319d0..fa596fc1f9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java @@ -10,6 +10,7 @@ import de.uka.ilkd.key.strategy.quantifierHeuristics.ClausesSmallerThanFeature; import de.uka.ilkd.key.strategy.termProjection.FocusProjection; +import org.key_project.logic.Name; import org.key_project.prover.strategy.costbased.feature.Feature; import org.key_project.prover.strategy.costbased.feature.SumFeature; import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; @@ -21,6 +22,7 @@ /// /// Do not create directly; use [JFOLStrategyFactory] instead. public class JFOLStrategy extends FOLStrategy { + public static final Name NAME = new Name("JFOL Strategy"); public JFOLStrategy(Proof proof, StrategyProperties strategyProperties) { super(proof, strategyProperties); @@ -72,4 +74,9 @@ protected void setupSplitting(RuleSetDispatchFeature d) { private Feature clausesSmallerThan(String smaller, String bigger, IntegerLDT numbers) { return ClausesSmallerThanFeature.create(instOf(smaller), instOf(bigger), numbers); } + + @Override + public Name name() { + return NAME; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 9c67239ecc..03a228e1bc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -128,15 +128,11 @@ protected Feature setupGlobalF(@NonNull Feature dispatcher) { depSpecF = ConditionalFeature.createConditional(depFilter, inftyConst()); } - final Feature oneStepSimplificationF = - oneStepSimplificationFeature(longConst(-11000)); - // final Feature smtF = smtFeature(inftyConst()); return SumFeature.createSum( // splitF, // strengthenConstraints, - oneStepSimplificationF, // smtF, queryF, depSpecF, dispatcher); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 271fba819b..0bdd40579d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -9,6 +9,7 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.OneStepSimplifier; import de.uka.ilkd.key.strategy.feature.AgeFeature; import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; import de.uka.ilkd.key.strategy.feature.NonDuplicateAppFeature; @@ -53,6 +54,8 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final Map> responsibilityMap; private final Map> ruleToStrategyMap = new LinkedHashMap<>(); + private final Map nameToStrategyMap = + new HashMap<>(); public ModularJavaDLStrategy(Proof proof, List componentStrategies, StrategyProperties properties) { @@ -62,20 +65,20 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); - conflictCostDispatcher = resolveConflicts(); - final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); - totalCost = - add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, - reduceCostTillMaxF, conflictCostDispatcher, - AgeFeature.INSTANCE, ifMatchedF); - responsibilityMap = new LinkedHashMap<>(strategies.size()); for (ComponentStrategy strategy : strategies) { + nameToStrategyMap.put(strategy.name(), strategy); var res = strategy.getResponsibilities(); for (var rs : res) { responsibilityMap.computeIfAbsent(rs, k -> new ArrayList<>()).add(strategy); } } + conflictCostDispatcher = resolveConflicts(); + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + totalCost = + add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, + reduceCostTillMaxF, conflictCostDispatcher, + AgeFeature.INSTANCE, ifMatchedF); } private record StratAndDispatcher(ComponentStrategy strategy, @@ -86,12 +89,12 @@ private RuleSetDispatchFeature resolveConflicts() { var dis = new RuleSetDispatchFeature(); var dispatchers = strategies.stream().map(s -> new StratAndDispatcher(s, s.getCostDispatcher())).toList(); - var map = new HashMap>(); + var map = new HashMap>(); for (var d : dispatchers) { var s = d.strategy; for (var rs : d.dispatcher.ruleSets()) { var lst = map.computeIfAbsent(rs, r -> new ArrayList<>()); - lst.add(s); + lst.add(s.name()); } } for (var e : map.entrySet()) { @@ -103,27 +106,27 @@ private RuleSetDispatchFeature resolveConflicts() { } private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, - List value) { + List stratNames) { switch (rs.name().toString()) { case "order_terms" -> { - var folStrat = value.getFirst(); - var intStrat = value.get(1); + var folStrat = nameToStrategyMap.get(stratNames.getFirst()); + var intStrat = nameToStrategyMap.get(stratNames.get(1)); bindRuleSet(d, "order_terms", ifZero(applyTF("commEqLeft", tf.intF), intStrat.getCostDispatcher().remove(rs), folStrat.getCostDispatcher().remove(rs))); } case "apply_equations" -> { - var folStrat = value.getFirst(); - var intStrat = value.get(1); + var folStrat = nameToStrategyMap.get(stratNames.getFirst()); + var intStrat = nameToStrategyMap.get(stratNames.get(1)); bindRuleSet(d, "apply_equations", ifZero(applyTF(FocusProjection.create(0), tf.intF), intStrat.getCostDispatcher().remove(rs), folStrat.getCostDispatcher().remove(rs))); } case "apply_equations_andOr" -> { - var folStrat = value.getFirst(); - var intStrat = value.get(1); + var folStrat = nameToStrategyMap.get(stratNames.getFirst()); + var intStrat = nameToStrategyMap.get(stratNames.get(1)); if (quantifierInstantiatedEnabled()) { bindRuleSet(d, "apply_equations_andOr", ifZero(applyTF(FocusProjection.create(0), tf.intF), @@ -187,12 +190,16 @@ private LinkedHashSet getResponsibleStrategies(Rule rule) { LinkedHashSet strats = ruleToStrategyMap.get(rule); if (strats == null) { strats = new LinkedHashSet<>(); - var ruleSets = rule.ruleSets(); - while (ruleSets.hasNext()) { - var rs = ruleSets.next(); - List s = responsibilityMap.get(rs); - if (s != null) - strats.addAll(s); + if (rule instanceof OneStepSimplifier) { + strats.add(nameToStrategyMap.get(JFOLStrategy.NAME)); + } else { + var ruleSets = rule.ruleSets(); + while (ruleSets.hasNext()) { + var rs = ruleSets.next(); + List s = responsibilityMap.get(rs); + if (s != null) + strats.addAll(s); + } } ruleToStrategyMap.put(rule, strats); } From 9d8f11f3d1da3a153e4e93acda448874ec797dda Mon Sep 17 00:00:00 2001 From: Drodt Date: Fri, 7 Nov 2025 10:36:54 +0100 Subject: [PATCH 48/62] Simplify conflict resolution --- .../key/strategy/ModularJavaDLStrategy.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 0bdd40579d..c8b140e216 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -99,34 +99,33 @@ private RuleSetDispatchFeature resolveConflicts() { } for (var e : map.entrySet()) { if (e.getValue().size() > 1) { - resolveConflict(dis, e.getKey(), e.getValue()); + resolveConflict(dis, e.getKey()); } } return dis; } - private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs, - List stratNames) { + private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs) { switch (rs.name().toString()) { case "order_terms" -> { - var folStrat = nameToStrategyMap.get(stratNames.getFirst()); - var intStrat = nameToStrategyMap.get(stratNames.get(1)); + var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); + var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); bindRuleSet(d, "order_terms", ifZero(applyTF("commEqLeft", tf.intF), intStrat.getCostDispatcher().remove(rs), folStrat.getCostDispatcher().remove(rs))); } case "apply_equations" -> { - var folStrat = nameToStrategyMap.get(stratNames.getFirst()); - var intStrat = nameToStrategyMap.get(stratNames.get(1)); + var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); + var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); bindRuleSet(d, "apply_equations", ifZero(applyTF(FocusProjection.create(0), tf.intF), intStrat.getCostDispatcher().remove(rs), folStrat.getCostDispatcher().remove(rs))); } case "apply_equations_andOr" -> { - var folStrat = nameToStrategyMap.get(stratNames.getFirst()); - var intStrat = nameToStrategyMap.get(stratNames.get(1)); + var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); + var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); if (quantifierInstantiatedEnabled()) { bindRuleSet(d, "apply_equations_andOr", ifZero(applyTF(FocusProjection.create(0), tf.intF), From dc90f0c25f596d3e5143602f38e0328d51a5f929 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 19 Nov 2025 08:02:30 +0100 Subject: [PATCH 49/62] Handle built-in rules --- .../uka/ilkd/key/strategy/ComponentStrategy.java | 7 +++++++ .../java/de/uka/ilkd/key/strategy/FOLStrategy.java | 7 +++++++ .../de/uka/ilkd/key/strategy/IntegerStrategy.java | 6 ++++++ .../uka/ilkd/key/strategy/JavaCardDLStrategy.java | 14 +++++++------- .../ilkd/key/strategy/ModularJavaDLStrategy.java | 10 +++++++--- .../de/uka/ilkd/key/strategy/StringStrategy.java | 6 ++++++ .../de/uka/ilkd/key/strategy/SymExStrategy.java | 13 +++++++++++++ 7 files changed, 53 insertions(+), 10 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java index f3a3f26bb1..f6e3732c93 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java @@ -6,12 +6,19 @@ import java.util.Set; import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; import org.key_project.prover.rules.RuleSet; public interface ComponentStrategy extends Strategy { + /// The strategy's cost dispatcher. RuleSetDispatchFeature getCostDispatcher(); + /// The rule sets this strategy is designed to handle. Set getResponsibilities(); + + /// Whether this strategy is responsible for the given [BuiltInRule]. This is necessary as + /// built-in rules have no rule sets. + boolean isResponsibleFor(BuiltInRule rule); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index e87c6a8795..3af619ff5a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -11,6 +11,8 @@ import de.uka.ilkd.key.logic.op.Quantifier; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.BuiltInRule; +import de.uka.ilkd.key.rule.OneStepSimplifier; import de.uka.ilkd.key.strategy.feature.*; import de.uka.ilkd.key.strategy.quantifierHeuristics.*; import de.uka.ilkd.key.strategy.termProjection.AssumptionProjection; @@ -615,4 +617,9 @@ private boolean normalSplitting() { return StrategyProperties.SPLITTING_NORMAL .equals(strategyProperties.getProperty(StrategyProperties.SPLITTING_OPTIONS_KEY)); } + + @Override + public boolean isResponsibleFor(BuiltInRule rule) { + return rule instanceof OneStepSimplifier; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 742fbe4307..e40512ce24 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -12,6 +12,7 @@ import de.uka.ilkd.key.logic.op.Junctor; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.*; import de.uka.ilkd.key.strategy.termProjection.*; import de.uka.ilkd.key.strategy.termgenerator.MultiplesModEquationsGenerator; @@ -1028,4 +1029,9 @@ public Name name() { public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } + + @Override + public boolean isResponsibleFor(BuiltInRule rule) { + return false; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 03a228e1bc..af09f4d680 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -11,12 +11,13 @@ import de.uka.ilkd.key.ldt.LocSetLDT; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.BuiltInRule; +import de.uka.ilkd.key.rule.QueryExpand; import de.uka.ilkd.key.rule.UseDependencyContractRule; import de.uka.ilkd.key.strategy.feature.*; import de.uka.ilkd.key.strategy.termProjection.*; import de.uka.ilkd.key.strategy.termfeature.*; import de.uka.ilkd.key.strategy.termgenerator.HeapGenerator; -import de.uka.ilkd.key.util.MiscTools; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -137,12 +138,6 @@ protected Feature setupGlobalF(@NonNull Feature dispatcher) { queryF, depSpecF, dispatcher); } - private Feature oneStepSimplificationFeature(Feature cost) { - SetRuleFilter filter = new SetRuleFilter(); - filter.addRuleToSet(MiscTools.findOneStepSimplifier(getProof())); - return ConditionalFeature.createConditional(filter, cost); - } - // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// // @@ -575,4 +570,9 @@ public boolean isStopAtFirstNonCloseableGoal() { public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } + + @Override + public boolean isResponsibleFor(BuiltInRule rule) { + return rule instanceof QueryExpand; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index c8b140e216..c8ac870410 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -9,7 +9,7 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; -import de.uka.ilkd.key.rule.OneStepSimplifier; +import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.AgeFeature; import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; import de.uka.ilkd.key.strategy.feature.NonDuplicateAppFeature; @@ -189,8 +189,12 @@ private LinkedHashSet getResponsibleStrategies(Rule rule) { LinkedHashSet strats = ruleToStrategyMap.get(rule); if (strats == null) { strats = new LinkedHashSet<>(); - if (rule instanceof OneStepSimplifier) { - strats.add(nameToStrategyMap.get(JFOLStrategy.NAME)); + if (rule instanceof BuiltInRule bir) { + for (var cs : strategies) { + if (cs.isResponsibleFor(bir)) { + strats.add(cs); + } + } } else { var ruleSets = rule.ruleSets(); while (ruleSets.hasNext()) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index 22d31ba7e1..d0ccbb79bf 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -12,6 +12,7 @@ import de.uka.ilkd.key.logic.op.SortDependingFunction; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.*; import de.uka.ilkd.key.strategy.termProjection.*; @@ -193,4 +194,9 @@ public Name name() { public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } + + @Override + public boolean isResponsibleFor(BuiltInRule rule) { + return false; + } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index 5f17ddd51b..8dd3b76da0 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -8,6 +8,8 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.*; +import de.uka.ilkd.key.rule.merge.MergeRule; import de.uka.ilkd.key.strategy.feature.*; import de.uka.ilkd.key.strategy.feature.findprefix.FindPrefixRestrictionFeature; import de.uka.ilkd.key.strategy.termProjection.TermBuffer; @@ -256,4 +258,15 @@ public Name name() { public RuleSetDispatchFeature getCostDispatcher() { return costComputationDispatcher; } + + @Override + public boolean isResponsibleFor(BuiltInRule rule) { + return rule instanceof WhileInvariantRule || rule instanceof LoopScopeInvariantRule + || rule instanceof BlockContractInternalRule + || rule instanceof BlockContractExternalRule + || rule instanceof LoopContractInternalRule + || rule instanceof LoopContractExternalRule + || rule instanceof LoopApplyHeadRule || rule instanceof UseOperationContractRule + || rule instanceof MergeRule; + } } From 9aba243af82a46c46de0b36d42532130f9276efc Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 19 Nov 2025 11:44:35 +0100 Subject: [PATCH 50/62] Fix ExprTests (relative paths) --- .../src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java | 1 + 1 file changed, 1 insertion(+) diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java index af8f010d43..b758e24d92 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/ParsingFacade.java @@ -77,6 +77,7 @@ public static List parseFiles(URL url) throws IOException { } catch (URISyntaxException e) { throw new IOException(e); } + path = path.getParent(); Collection includes = ctx.getIncludes(path).getRuleSets(); for (RuleSource u : includes) { if (!reached.contains(u.url())) { From 393cee7c5a9df8d084824a42c585f391bfdd5471 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 19 Nov 2025 11:52:08 +0100 Subject: [PATCH 51/62] Regenerate taclet oracle --- .../de/uka/ilkd/key/nparser/taclets.old.txt | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/key.core/src/test/resources/de/uka/ilkd/key/nparser/taclets.old.txt b/key.core/src/test/resources/de/uka/ilkd/key/nparser/taclets.old.txt index a95305f3db..212869c6f5 100644 --- a/key.core/src/test/resources/de/uka/ilkd/key/nparser/taclets.old.txt +++ b/key.core/src/test/resources/de/uka/ilkd/key/nparser/taclets.old.txt @@ -1,5 +1,5 @@ # This files contains representation of taclets, which are accepted and revised. -# Date: Tue Jul 29 22:37:48 CEST 2025 +# Date: Wed Nov 19 11:46:34 CET 2025 == abortJavaCardTransactionAPI (abortJavaCardTransactionAPI) ========================================= abortJavaCardTransactionAPI { @@ -1148,7 +1148,7 @@ array_self_reference { \assumes ([wellFormed(heapSV)]==>[equals(array,null)]) \find(arrayStoreValid(array,G::select(heapSV,array,arr(idx)))) \sameUpdateLevel\replacewith(true) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == array_self_reference_eq (array_self_reference_eq) ========================================= @@ -1156,7 +1156,7 @@ array_self_reference_eq { \assumes ([wellFormed(heapSV),equals(G::select(heapSV,array,arr(idx)),EQ)]==>[equals(array,null)]) \find(arrayStoreValid(array,EQ)) \sameUpdateLevel\replacewith(true) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == array_store_known_dynamic_array_type (known dynamic array type) ========================================= @@ -1165,7 +1165,7 @@ array_store_known_dynamic_array_type { \find(arrayStoreValid(array,obj)) \sameUpdateLevel\varcond(\isReference[non_null]( J )) \replacewith(or(equals(obj,null),equals(#arrayBaseInstanceOf(J::exactInstance(array),obj),TRUE))) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == asinIsNaN (asinIsNaN) ========================================= @@ -10007,7 +10007,7 @@ ifElseSkipElse { #loc = true; #s0 ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifElseSkipElseConditionInBlock (ifElseSkipElse) ========================================= @@ -10025,7 +10025,7 @@ ifElseSkipElseConditionInBlock { } #s0 ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifElseSkipThen (ifElseSkipThen) ========================================= @@ -10039,7 +10039,7 @@ ifElseSkipThen { #loc = false; #s1 ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifElseSkipThenConditionInBlock (ifElseSkipThen) ========================================= @@ -10057,7 +10057,7 @@ ifElseSkipThenConditionInBlock { } #s1 ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifElseSplit (ifElseSplit) ========================================= @@ -10131,7 +10131,7 @@ ifEnterThen { #loc = true; #s0 ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifEnterThenConditionInBlock (ifEnterThen) ========================================= @@ -10148,7 +10148,7 @@ ifEnterThenConditionInBlock { } #s0 ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifEqualsInteger (ifEqualsInteger) ========================================= @@ -10337,7 +10337,7 @@ ifSkipThen { \replacewith(#allmodal ((modal operator))|{{ .. #loc = false; ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifSkipThenConditionInBlock (ifSkipThen) ========================================= @@ -10353,7 +10353,7 @@ ifSkipThenConditionInBlock { #loc = false; } ... }}| (post)) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == ifSplit (ifElseSplit) ========================================= @@ -11307,7 +11307,7 @@ Choices: true} insert_constant_value { \find(#cv) \replacewith(#constantvalue(#cv)) -\heuristics(concrete) +\heuristics(concrete_java) Choices: programRules:Java} ----------------------------------------------------- == insert_eq_all (insert_eq_all) ========================================= @@ -11633,12 +11633,6 @@ intersectionSetMinusItself_2 { \heuristics(concrete) Choices: programRules:Java} ----------------------------------------------------- -== introduceAxiom (introduceAxiom) ========================================= -introduceAxiom { -\add [cutFormula]==>[] - -Choices: true} ------------------------------------------------------ == irrflConcrete1 (irrflConcrete1) ========================================= irrflConcrete1 { \find(lt(i,i)==>) @@ -13931,7 +13925,7 @@ null_can_always_be_stored_in_a_reference_type_array { \find(arrayStoreValid(array,null)) \sameUpdateLevel\varcond(\isReferenceArray(array (GOS term))) \replacewith(true) -\heuristics(simplify) +\heuristics(simplify_java) Choices: programRules:Java} ----------------------------------------------------- == observerDependency (observerDependency) ========================================= From f3d3aa16da91548aeb865bffe299c8e992fd2e36 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 19 Nov 2025 13:02:34 +0100 Subject: [PATCH 52/62] Fix OSS --- .../main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java b/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java index 5a6461e885..c04e03ef18 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java @@ -81,10 +81,11 @@ public static final class Protocol extends ArrayList { * "evaluate_instanceof"; in any case there was a measurable slowdown. -- DB 03/06/14 */ private static final ImmutableList ruleSets = ImmutableSLList.nil() - .append("concrete").append("update_elim").append("update_apply_on_update") + .append("concrete").append("concrete_java").append("update_elim") + .append("update_apply_on_update") .append("update_apply").append("update_join").append("elimQuantifier"); - private static final boolean[] bottomUp = { false, false, true, true, true, false }; + private static final boolean[] bottomUp = { false, false, false, true, true, true, false }; private final Map applicabilityCache = new LRUCache<>(APPLICABILITY_CACHE_SIZE); From 1c2967d7a634a5d152ae3d5f92a4f96796aac5d1 Mon Sep 17 00:00:00 2001 From: Drodt Date: Wed, 19 Nov 2025 13:11:56 +0100 Subject: [PATCH 53/62] Add missing Builtin rule to JavaDL strat --- .../main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index af09f4d680..402a3baf22 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -573,6 +573,6 @@ public RuleSetDispatchFeature getCostDispatcher() { @Override public boolean isResponsibleFor(BuiltInRule rule) { - return rule instanceof QueryExpand; + return rule instanceof QueryExpand || rule instanceof UseDependencyContractRule; } } From 59f8432b4f252dfcf289b5d2d6b84a4d1f414a44 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Thu, 20 Nov 2025 15:33:58 +0100 Subject: [PATCH 54/62] Strategy Dispatcher API refactoring (work-in-progress; does not yet compile) --- .../ilkd/key/strategy/ComponentStrategy.java | 10 +++- .../de/uka/ilkd/key/strategy/FOLStrategy.java | 32 +++++------ .../ilkd/key/strategy/IntegerStrategy.java | 23 ++++---- .../ilkd/key/strategy/JavaCardDLStrategy.java | 37 +++++++------ .../key/strategy/ModularJavaDLStrategy.java | 54 ++++++++++++------- .../uka/ilkd/key/strategy/StringStrategy.java | 29 ++++++---- .../uka/ilkd/key/strategy/SymExStrategy.java | 23 +++++--- 7 files changed, 123 insertions(+), 85 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java index f6e3732c93..8e0e47a323 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java @@ -9,14 +9,20 @@ import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; +import org.jspecify.annotations.Nullable; import org.key_project.prover.rules.RuleSet; public interface ComponentStrategy extends Strategy { + + enum StrategyAspect { + Cost, Instantiation, Approval; + } + /// The strategy's cost dispatcher. - RuleSetDispatchFeature getCostDispatcher(); + RuleSetDispatchFeature getDispatcher(StrategyAspect aspect); /// The rule sets this strategy is designed to handle. - Set getResponsibilities(); + Set getResponsibilities(StrategyAspect aspect); /// Whether this strategy is responsible for the given [BuiltInRule]. This is necessary as /// built-in rules have no rule sets. diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index 3af619ff5a..2d0680f008 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -212,18 +212,19 @@ public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, } @Override - public RuleSetDispatchFeature getCostDispatcher() { - return costComputationDispatcher; - } - - @Override - public boolean isStopAtFirstNonCloseableGoal() { - return false; + public Set getResponsibilities(StrategyAspect aspect) { + var set = new HashSet(); + set.addAll(getDispatcher(aspect).ruleSets()); + return set; } @Override - public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return approvalF.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; + public RuleSetDispatchFeature getDispatcher(StrategyAspect aspect) { + return switch (aspect) { + case StrategyAspect.Cost -> costComputationDispatcher; + case StrategyAspect.Instantiation -> instantiationDispatcher; + case StrategyAspect.Approval -> approvalDispatcher; + }; } @Override @@ -233,12 +234,13 @@ public boolean isResponsibleFor(RuleSet rs) { } @Override - public Set getResponsibilities() { - var set = new HashSet(); - set.addAll(costComputationDispatcher.ruleSets()); - set.addAll(instantiationDispatcher.ruleSets()); - set.addAll(approvalDispatcher.ruleSets()); - return set; + public boolean isStopAtFirstNonCloseableGoal() { + return false; + } + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return approvalF.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; } @Override diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index e40512ce24..85da5d6c65 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -97,14 +97,6 @@ public boolean isResponsibleFor(RuleSet rs) { return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; } - @Override - public Set getResponsibilities() { - var set = new HashSet(); - set.addAll(costComputationDispatcher.ruleSets()); - set.addAll(instantiationDispatcher.ruleSets()); - return set; - } - private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); @@ -1026,8 +1018,19 @@ public Name name() { } @Override - public RuleSetDispatchFeature getCostDispatcher() { - return costComputationDispatcher; + public Set getResponsibilities(StrategyAspect aspect) { + var set = new HashSet(); + set.addAll(getDispatcher(aspect).ruleSets()); + return set; + } + + @Override + public RuleSetDispatchFeature getDispatcher(StrategyAspect aspect) { + return switch (aspect) { + case StrategyAspect.Cost -> costComputationDispatcher; + case StrategyAspect.Instantiation -> instantiationDispatcher; + case StrategyAspect.Approval -> approvalDispatcher; + }; } @Override diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 402a3baf22..5f42ce0910 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -78,27 +78,31 @@ protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) approvalF = add(setupApprovalF(), approvalDispatcher); } + protected final RuleSetDispatchFeature getCostComputationDispatcher() { return costComputationDispatcher; } - protected final RuleSetDispatchFeature getInstantiationDispatcher() { - return instantiationDispatcher; + @Override + public Set getResponsibilities(StrategyAspect aspect) { + var set = new HashSet(); + set.addAll(getDispatcher(aspect).ruleSets()); + return set; } @Override - public boolean isResponsibleFor(RuleSet rs) { - return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null - || approvalDispatcher.get(rs) != null; + public RuleSetDispatchFeature getDispatcher(StrategyAspect aspect) { + return switch (aspect) { + case StrategyAspect.Cost -> costComputationDispatcher; + case StrategyAspect.Instantiation -> instantiationDispatcher; + case StrategyAspect.Approval -> approvalDispatcher; + }; } @Override - public Set getResponsibilities() { - var set = new HashSet(); - set.addAll(costComputationDispatcher.ruleSets()); - set.addAll(instantiationDispatcher.ruleSets()); - set.addAll(approvalDispatcher.ruleSets()); - return set; + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null + || approvalDispatcher.get(rs) != null; } protected Feature setupGlobalF(@NonNull Feature dispatcher) { @@ -389,7 +393,7 @@ protected Feature setupApprovalF() { depSpecF = ConditionalFeature.createConditional(depFilter, inftyConst()); } - return add(NonDuplicateAppFeature.INSTANCE, depSpecF); + return depSpecF; // add(NonDuplicateAppFeature.INSTANCE, depSpecF); } private RuleSetDispatchFeature setupApprovalDispatcher() { @@ -439,13 +443,13 @@ private void setupClassAxiomApproval(final RuleSetDispatchFeature d) { /* * can be applied if sv_heap is instantiated or not present */ - not(needsInstantiation), approveInst, NonDuplicateAppFeature.INSTANCE)); + not(needsInstantiation), approveInst));//, NonDuplicateAppFeature.INSTANCE)); } else { bindRuleSet(d, "classAxiom", add( /* * can be applied if sv_heap is instantiated or not present */ - not(needsInstantiation), approveInst, NonDuplicateAppFeature.INSTANCE)); + not(needsInstantiation), approveInst));//, NonDuplicateAppFeature.INSTANCE)); } } else { bindRuleSet(d, "classAxiom", inftyConst()); @@ -566,11 +570,6 @@ public boolean isStopAtFirstNonCloseableGoal() { .equals(StrategyProperties.STOPMODE_NONCLOSE); } - @Override - public RuleSetDispatchFeature getCostDispatcher() { - return costComputationDispatcher; - } - @Override public boolean isResponsibleFor(BuiltInRule rule) { return rule instanceof QueryExpand || rule instanceof UseDependencyContractRule; diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index c8ac870410..d7382bf28e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -10,6 +10,7 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.BuiltInRule; +import de.uka.ilkd.key.strategy.ComponentStrategy.StrategyAspect; import de.uka.ilkd.key.strategy.feature.AgeFeature; import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; import de.uka.ilkd.key.strategy.feature.NonDuplicateAppFeature; @@ -51,7 +52,9 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final ArithTermFeatures tf; private final RuleSetDispatchFeature conflictCostDispatcher; private final Feature totalCost; - private final Map> responsibilityMap; + private final Map> costResponsibilityMap; + private final Map> instantiationResponsibilityMap; + private final Map> approvalResponsibilityMap; private final Map> ruleToStrategyMap = new LinkedHashMap<>(); private final Map nameToStrategyMap = @@ -65,14 +68,14 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); - responsibilityMap = new LinkedHashMap<>(strategies.size()); - for (ComponentStrategy strategy : strategies) { - nameToStrategyMap.put(strategy.name(), strategy); - var res = strategy.getResponsibilities(); - for (var rs : res) { - responsibilityMap.computeIfAbsent(rs, k -> new ArrayList<>()).add(strategy); - } - } + costResponsibilityMap = new LinkedHashMap<>(strategies.size()); + instantiationResponsibilityMap = new LinkedHashMap<>(strategies.size()); + approvalResponsibilityMap = new LinkedHashMap<>(strategies.size()); + + initializeResponsibilityMap(StrategyAspect.Cost, costResponsibilityMap); + initializeResponsibilityMap(StrategyAspect.Instantiation, instantiationResponsibilityMap); + initializeResponsibilityMap(StrategyAspect.Approval, approvalResponsibilityMap); + conflictCostDispatcher = resolveConflicts(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); totalCost = @@ -81,6 +84,17 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat AgeFeature.INSTANCE, ifMatchedF); } + private void initializeResponsibilityMap(StrategyAspect aspect, + Map> responsibilityMap) { + for (ComponentStrategy strategy : strategies) { + nameToStrategyMap.put(strategy.name(), strategy); + var res = strategy.getResponsibilities(aspect); + for (var rs : res) { + responsibilityMap.computeIfAbsent(rs, k -> new ArrayList<>()).add(strategy); + } + } + } + private record StratAndDispatcher(ComponentStrategy strategy, RuleSetDispatchFeature dispatcher) { } @@ -88,7 +102,7 @@ private record StratAndDispatcher(ComponentStrategy strategy, private RuleSetDispatchFeature resolveConflicts() { var dis = new RuleSetDispatchFeature(); var dispatchers = - strategies.stream().map(s -> new StratAndDispatcher(s, s.getCostDispatcher())).toList(); + strategies.stream().map(s -> new StratAndDispatcher(s, s.getDispatcher(StrategyAspect.Cost))).toList(); var map = new HashMap>(); for (var d : dispatchers) { var s = d.strategy; @@ -112,16 +126,16 @@ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs) { var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); bindRuleSet(d, "order_terms", ifZero(applyTF("commEqLeft", tf.intF), - intStrat.getCostDispatcher().remove(rs), - folStrat.getCostDispatcher().remove(rs))); + intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), + folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); } case "apply_equations" -> { var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); bindRuleSet(d, "apply_equations", ifZero(applyTF(FocusProjection.create(0), tf.intF), - intStrat.getCostDispatcher().remove(rs), - folStrat.getCostDispatcher().remove(rs))); + intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), + folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); } case "apply_equations_andOr" -> { var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); @@ -129,8 +143,8 @@ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs) { if (quantifierInstantiatedEnabled()) { bindRuleSet(d, "apply_equations_andOr", ifZero(applyTF(FocusProjection.create(0), tf.intF), - intStrat.getCostDispatcher().remove(rs), - folStrat.getCostDispatcher().remove(rs))); + intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), + folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); } else { bindRuleSet(d, "apply_equations_andOr", inftyConst()); } @@ -164,7 +178,7 @@ public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; return reduceTillMax(app, isApproved, false, Boolean::logicalAnd, - s -> s.isApprovedApp(app, pio, goal)); + s -> s.isApprovedApp(app, pio, goal), getResponsibleStrategies(StrategyAspect.Approval)); } @Override @@ -173,8 +187,7 @@ public Name name() { } private R reduceTillMax(RuleApp app, R init, R max, BiFunction accumulator, - Function mapper) { - LinkedHashSet strats = getResponsibleStrategies(app.rule()); + Function mapper, LinkedHashSet strats) { for (ComponentStrategy strategy : strats) { init = accumulator.apply(init, mapper.apply(strategy)); @@ -185,7 +198,8 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu return init; } - private LinkedHashSet getResponsibleStrategies(Rule rule) { + private LinkedHashSet getResponsibleStrategies(Rule rule, + Map responsibilityMap) { LinkedHashSet strats = ruleToStrategyMap.get(rule); if (strats == null) { strats = new LinkedHashSet<>(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index d0ccbb79bf..e4e18e0879 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -14,7 +14,6 @@ import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.*; -import de.uka.ilkd.key.strategy.termProjection.*; import org.key_project.logic.Name; import org.key_project.prover.proof.ProofGoal; @@ -23,7 +22,6 @@ import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; -import org.key_project.prover.strategy.costbased.TopRuleAppCost; import org.key_project.prover.strategy.costbased.feature.Feature; import org.key_project.prover.strategy.costbased.feature.SumFeature; import org.key_project.prover.strategy.costbased.termfeature.OperatorClassTF; @@ -64,11 +62,6 @@ public boolean isResponsibleFor(RuleSet rs) { return costComputationDispatcher.get(rs) != null; } - @Override - public Set getResponsibilities() { - return new HashSet<>(costComputationDispatcher.ruleSets()); - } - private RuleSetDispatchFeature setupCostComputationF() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); setUpStringNormalisation(d); @@ -169,8 +162,9 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { - return NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, - new MutableState()) != TopRuleAppCost.INSTANCE; + return true; + /* NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, + new MutableState()) != TopRuleAppCost.INSTANCE;*/ } @Override @@ -191,8 +185,21 @@ public Name name() { } @Override - public RuleSetDispatchFeature getCostDispatcher() { - return costComputationDispatcher; + public Set getResponsibilities(StrategyAspect aspect) { + var set = new HashSet(); + RuleSetDispatchFeature dispatcher = getDispatcher(aspect); + if (dispatcher != null) { + set.addAll(dispatcher.ruleSets()); + } + return set; + } + + @Override + public RuleSetDispatchFeature getDispatcher(StrategyAspect aspect) { + return switch (aspect) { + case StrategyAspect.Cost -> costComputationDispatcher; + default -> null; + }; } @Override diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java index 8dd3b76da0..d4c55df36d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -64,13 +64,25 @@ public boolean isResponsibleFor(RuleSet rs) { } @Override - public Set getResponsibilities() { + public Set getResponsibilities(StrategyAspect aspect) { var set = new HashSet(); - set.addAll(costComputationDispatcher.ruleSets()); - set.addAll(instantiationDispatcher.ruleSets()); + RuleSetDispatchFeature dispatcher = getDispatcher(aspect); + if (dispatcher != null) { + set.addAll(dispatcher.ruleSets()); + } return set; } + @Override + public RuleSetDispatchFeature getDispatcher(StrategyAspect aspect) { + return switch (aspect) { + case StrategyAspect.Cost -> costComputationDispatcher; + case StrategyAspect.Instantiation -> instantiationDispatcher; + default -> null; + }; + } + + private Feature setupGlobalF(Feature dispatcher) { final Feature methodSpecF; final String methProp = @@ -254,11 +266,6 @@ public Name name() { return costComputationF.computeCost(app, pos, goal, mState); } - @Override - public RuleSetDispatchFeature getCostDispatcher() { - return costComputationDispatcher; - } - @Override public boolean isResponsibleFor(BuiltInRule rule) { return rule instanceof WhileInvariantRule || rule instanceof LoopScopeInvariantRule From 54c96185508569b5319730afe98a6c7de7077d67 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 20 Nov 2025 16:01:20 +0100 Subject: [PATCH 55/62] Fix reworked dispatch seprataion --- .../strategy/SymbolicExecutionStrategy.java | 2 +- .../ilkd/key/strategy/ComponentStrategy.java | 1 - .../ilkd/key/strategy/JavaCardDLStrategy.java | 4 +- .../key/strategy/ModularJavaDLStrategy.java | 39 +++++++++++++------ .../uka/ilkd/key/strategy/StringStrategy.java | 6 ++- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java index e4ac308db6..515695c1e7 100644 --- a/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java +++ b/key.core.symbolic_execution/src/main/java/de/uka/ilkd/key/symbolic_execution/strategy/SymbolicExecutionStrategy.java @@ -84,7 +84,7 @@ private SymbolicExecutionStrategy(Proof proof, StrategyProperties sp) { .equals(sp.get(StrategyProperties.SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY))) { // Make sure that an immediately alias check is performed by doing cuts of objects to // find out if they can be the same or not - RuleSetDispatchFeature instRsd = getInstantiationDispatcher(); + RuleSetDispatchFeature instRsd = getDispatcher(StrategyAspect.Instantiation); enableInstantiate(); final TermBuffer buffer = new TermBuffer<>(); Feature originalCut = instRsd.get(getHeuristic("cut")); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java index 8e0e47a323..9c5bde140d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java @@ -9,7 +9,6 @@ import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; -import org.jspecify.annotations.Nullable; import org.key_project.prover.rules.RuleSet; public interface ComponentStrategy extends Strategy { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 5f42ce0910..afe6e7bdea 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java @@ -443,13 +443,13 @@ private void setupClassAxiomApproval(final RuleSetDispatchFeature d) { /* * can be applied if sv_heap is instantiated or not present */ - not(needsInstantiation), approveInst));//, NonDuplicateAppFeature.INSTANCE)); + not(needsInstantiation), approveInst));// , NonDuplicateAppFeature.INSTANCE)); } else { bindRuleSet(d, "classAxiom", add( /* * can be applied if sv_heap is instantiated or not present */ - not(needsInstantiation), approveInst));//, NonDuplicateAppFeature.INSTANCE)); + not(needsInstantiation), approveInst));// , NonDuplicateAppFeature.INSTANCE)); } } else { bindRuleSet(d, "classAxiom", inftyConst()); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index d7382bf28e..16a003339b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -55,7 +55,11 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final Map> costResponsibilityMap; private final Map> instantiationResponsibilityMap; private final Map> approvalResponsibilityMap; - private final Map> ruleToStrategyMap = + private final Map> costRuleToStrategyMap = + new LinkedHashMap<>(); + private final Map> instantiationRuleToStrategyMap = + new LinkedHashMap<>(); + private final Map> approvalRuleToStrategyMap = new LinkedHashMap<>(); private final Map nameToStrategyMap = new HashMap<>(); @@ -64,8 +68,6 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat StrategyProperties properties) { super(proof); strategies.addAll(componentStrategies); - reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost); - reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp); this.strategyProperties = (StrategyProperties) properties.clone(); this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); costResponsibilityMap = new LinkedHashMap<>(strategies.size()); @@ -78,6 +80,11 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat conflictCostDispatcher = resolveConflicts(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost, + (rule) -> getResponsibleStrategies(rule, costResponsibilityMap, costRuleToStrategyMap)); + reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp, + (rule) -> getResponsibleStrategies(rule, instantiationResponsibilityMap, + instantiationRuleToStrategyMap)); totalCost = add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, reduceCostTillMaxF, conflictCostDispatcher, @@ -85,7 +92,7 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat } private void initializeResponsibilityMap(StrategyAspect aspect, - Map> responsibilityMap) { + Map> responsibilityMap) { for (ComponentStrategy strategy : strategies) { nameToStrategyMap.put(strategy.name(), strategy); var res = strategy.getResponsibilities(aspect); @@ -102,7 +109,9 @@ private record StratAndDispatcher(ComponentStrategy strategy, private RuleSetDispatchFeature resolveConflicts() { var dis = new RuleSetDispatchFeature(); var dispatchers = - strategies.stream().map(s -> new StratAndDispatcher(s, s.getDispatcher(StrategyAspect.Cost))).toList(); + strategies.stream() + .map(s -> new StratAndDispatcher(s, s.getDispatcher(StrategyAspect.Cost))) + .toList(); var map = new HashMap>(); for (var d : dispatchers) { var s = d.strategy; @@ -177,8 +186,9 @@ public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { boolean isApproved = NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; - return reduceTillMax(app, isApproved, false, Boolean::logicalAnd, - s -> s.isApprovedApp(app, pio, goal), getResponsibleStrategies(StrategyAspect.Approval)); + return reduceTillMax(isApproved, false, Boolean::logicalAnd, + s -> s.isApprovedApp(app, pio, goal), getResponsibleStrategies(app.rule(), + approvalResponsibilityMap, approvalRuleToStrategyMap)); } @Override @@ -186,7 +196,7 @@ public Name name() { return NAME; } - private R reduceTillMax(RuleApp app, R init, R max, BiFunction accumulator, + private R reduceTillMax(R init, R max, BiFunction accumulator, Function mapper, LinkedHashSet strats) { for (ComponentStrategy strategy : strats) { @@ -199,7 +209,8 @@ private R reduceTillMax(RuleApp app, R init, R max, BiFunction accu } private LinkedHashSet getResponsibleStrategies(Rule rule, - Map responsibilityMap) { + Map> responsibilityMap, + Map> ruleToStrategyMap) { LinkedHashSet strats = ruleToStrategyMap.get(rule); if (strats == null) { strats = new LinkedHashSet<>(); @@ -237,16 +248,20 @@ RuleAppCost compute(ComponentStrategy strategy, RuleApp app, private class ReduceTillMaxFeature implements Feature { private final StrategyCostFunction mapper; + private final Function> ruleToStrategy; - ReduceTillMaxFeature(StrategyCostFunction mapper) { + ReduceTillMaxFeature(StrategyCostFunction mapper, + Function> ruleToStrategy) { this.mapper = mapper; + this.ruleToStrategy = ruleToStrategy; } @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { - return reduceTillMax(app, NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, - RuleAppCost::add, s -> mapper.compute(s, app, pos, (Goal) goal, mState)); + return reduceTillMax(NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, + RuleAppCost::add, s -> mapper.compute(s, app, pos, (Goal) goal, mState), + ruleToStrategy.apply(app.rule())); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java index e4e18e0879..06600a5cdb 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -163,8 +163,10 @@ public boolean isStopAtFirstNonCloseableGoal() { @Override public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { return true; - /* NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, - new MutableState()) != TopRuleAppCost.INSTANCE;*/ + /* + * NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, + * new MutableState()) != TopRuleAppCost.INSTANCE; + */ } @Override From f8d79b3301d0b161d3eb088a9dcdf329b485b6ee Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Thu, 20 Nov 2025 16:40:05 +0100 Subject: [PATCH 56/62] Fix performance regression (add fail fast in approval logic) --- .../de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 16a003339b..48c3e66840 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -80,11 +80,14 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat conflictCostDispatcher = resolveConflicts(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost, (rule) -> getResponsibleStrategies(rule, costResponsibilityMap, costRuleToStrategyMap)); + reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp, (rule) -> getResponsibleStrategies(rule, instantiationResponsibilityMap, instantiationRuleToStrategyMap)); + totalCost = add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, reduceCostTillMaxF, conflictCostDispatcher, @@ -186,6 +189,9 @@ public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { boolean isApproved = NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, new MutableState()) != TopRuleAppCost.INSTANCE; + if (!isApproved) { + return false; + } return reduceTillMax(isApproved, false, Boolean::logicalAnd, s -> s.isApprovedApp(app, pio, goal), getResponsibleStrategies(app.rule(), approvalResponsibilityMap, approvalRuleToStrategyMap)); From 164065db23c1bb2199196716c117f08c24d51fe6 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 21 Nov 2025 09:26:11 +0100 Subject: [PATCH 57/62] Minor cleanup and correction (approval feature and cost feature were out-of-sync) --- .../key/strategy/ModularJavaDLStrategy.java | 31 +++++++++---------- .../quantifierHeuristics/Substitution.java | 3 +- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 48c3e66840..ce7756fecb 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -52,17 +52,19 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final ArithTermFeatures tf; private final RuleSetDispatchFeature conflictCostDispatcher; private final Feature totalCost; - private final Map> costResponsibilityMap; - private final Map> instantiationResponsibilityMap; - private final Map> approvalResponsibilityMap; + private final Map> costResponsibilityMap = + new LinkedHashMap<>(); + private final Map> instantiationResponsibilityMap = + new LinkedHashMap<>(); + private final Map> approvalResponsibilityMap = + new LinkedHashMap<>(); private final Map> costRuleToStrategyMap = new LinkedHashMap<>(); private final Map> instantiationRuleToStrategyMap = new LinkedHashMap<>(); private final Map> approvalRuleToStrategyMap = new LinkedHashMap<>(); - private final Map nameToStrategyMap = - new HashMap<>(); + private final Map nameToStrategyMap = new HashMap<>(); public ModularJavaDLStrategy(Proof proof, List componentStrategies, StrategyProperties properties) { @@ -70,17 +72,14 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat strategies.addAll(componentStrategies); this.strategyProperties = (StrategyProperties) properties.clone(); this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); - costResponsibilityMap = new LinkedHashMap<>(strategies.size()); - instantiationResponsibilityMap = new LinkedHashMap<>(strategies.size()); - approvalResponsibilityMap = new LinkedHashMap<>(strategies.size()); initializeResponsibilityMap(StrategyAspect.Cost, costResponsibilityMap); initializeResponsibilityMap(StrategyAspect.Instantiation, instantiationResponsibilityMap); initializeResponsibilityMap(StrategyAspect.Approval, approvalResponsibilityMap); conflictCostDispatcher = resolveConflicts(); - final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost, (rule) -> getResponsibleStrategies(rule, costResponsibilityMap, costRuleToStrategyMap)); @@ -89,9 +88,8 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat instantiationRuleToStrategyMap)); totalCost = - add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, - reduceCostTillMaxF, conflictCostDispatcher, - AgeFeature.INSTANCE, ifMatchedF); + add(AutomatedRuleFeature.getInstance(), ifMatchedF, NonDuplicateAppFeature.INSTANCE, + reduceCostTillMaxF, conflictCostDispatcher, AgeFeature.INSTANCE); } private void initializeResponsibilityMap(StrategyAspect aspect, @@ -170,10 +168,10 @@ public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, MutableState mState) { enableInstantiate(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); - Feature totalCost = - add(AutomatedRuleFeature.getInstance(), NonDuplicateAppFeature.INSTANCE, - reduceInstTillMaxF, - AgeFeature.INSTANCE, ifMatchedF); + final Feature conflictCostDispatcher = resolveConflicts(); + final Feature totalCost = + add(AutomatedRuleFeature.getInstance(), ifMatchedF, NonDuplicateAppFeature.INSTANCE, + conflictCostDispatcher, reduceInstTillMaxF, AgeFeature.INSTANCE); disableInstantiate(); return totalCost.computeCost(app, pio, goal, mState); } @@ -204,7 +202,6 @@ public Name name() { private R reduceTillMax(R init, R max, BiFunction accumulator, Function mapper, LinkedHashSet strats) { - for (ComponentStrategy strategy : strats) { init = accumulator.apply(init, mapper.apply(strategy)); if (init == max) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Substitution.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Substitution.java index 457218bd68..cafa348a2c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Substitution.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Substitution.java @@ -88,8 +88,7 @@ public Term apply(Term t, Services services) { private Term applySubst(QuantifiableVariable var, Term instance, Term t, TermBuilder tb) { final ClashFreeSubst subst = - new ClashFreeSubst(var, - (JTerm) instance, tb); + new ClashFreeSubst(var, (JTerm) instance, tb); return subst.apply((JTerm) t); } From ee753feef4b363c8017c2ad16c694eff49404c4e Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Fri, 21 Nov 2025 09:36:20 +0100 Subject: [PATCH 58/62] added some comments --- .../key/strategy/ModularJavaDLStrategy.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index ce7756fecb..758f730b1a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -52,12 +52,18 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { private final ArithTermFeatures tf; private final RuleSetDispatchFeature conflictCostDispatcher; private final Feature totalCost; + + // map rulesets to the strategies that participate in their cost computations, instantiation or + // approval decisions private final Map> costResponsibilityMap = new LinkedHashMap<>(); private final Map> instantiationResponsibilityMap = new LinkedHashMap<>(); private final Map> approvalResponsibilityMap = new LinkedHashMap<>(); + + // map rules to the strategies that participate in their cost computations, instantiation or + // approval decisions private final Map> costRuleToStrategyMap = new LinkedHashMap<>(); private final Map> instantiationRuleToStrategyMap = @@ -77,6 +83,9 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat initializeResponsibilityMap(StrategyAspect.Instantiation, instantiationResponsibilityMap); initializeResponsibilityMap(StrategyAspect.Approval, approvalResponsibilityMap); + // if more than one strategy is responsible for a _ruleset_ we need to determine how to + // resolve the + // competing computations conflictCostDispatcher = resolveConflicts(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); @@ -87,11 +96,18 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat (rule) -> getResponsibleStrategies(rule, instantiationResponsibilityMap, instantiationRuleToStrategyMap)); + // the feature for the cost computation totalCost = add(AutomatedRuleFeature.getInstance(), ifMatchedF, NonDuplicateAppFeature.INSTANCE, reduceCostTillMaxF, conflictCostDispatcher, AgeFeature.INSTANCE); } + /** + * Caches the information which strategies are responsible for which ruleset + * + * @param aspect the StrategyAspect for which the cache is created + * @param responsibilityMap the map used as cache for the specified aspect + */ private void initializeResponsibilityMap(StrategyAspect aspect, Map> responsibilityMap) { for (ComponentStrategy strategy : strategies) { @@ -107,6 +123,13 @@ private record StratAndDispatcher(ComponentStrategy strategy, RuleSetDispatchFeature dispatcher) { } + /** + * checks for conflicts and resolves known ones (in case an unknown conflict is encountered the + * method fails + * with a runtime exception + * + * @return the feature implementing the conflict resolution + */ private RuleSetDispatchFeature resolveConflicts() { var dis = new RuleSetDispatchFeature(); var dispatchers = @@ -129,6 +152,13 @@ private RuleSetDispatchFeature resolveConflicts() { return dis; } + /** + * resolves known conflicts + * + * @param d the RuleSetDispatchFeature to which the conflict resolution will be bound + * @param rs the RuleSet for which a conflict resolution is required + * @throws IllegalArgumentException if the conflict cannot be resolved + */ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs) { switch (rs.name().toString()) { case "order_terms" -> { From 3429b98733f364e85b5e0b2e89ddfafe19b8c0de Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 11 Dec 2025 14:32:47 +0100 Subject: [PATCH 59/62] Remove erroneous(?) third slash in URI --- .../java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java index f33f633dc2..a6a2e278f1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java @@ -62,7 +62,7 @@ private void addInclude(String filename) throws MalformedURLException { var path = base.resolve(filename).normalize(); var uri = URI.create(path.toString()); if (uri.getScheme() == null) { - uri = URI.create("file:///" + path); + uri = URI.create("file://" + path); } URL url = uri.toURL(); source = RuleSourceFactory.initRuleFile(url); From 7884f767c310d31fcd1f42cdfce69ecece2acfe8 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 11 Dec 2025 15:10:54 +0100 Subject: [PATCH 60/62] Refactor ModularStrat; add Documentation --- .../ilkd/key/strategy/ComponentStrategy.java | 1 - .../key/strategy/ModularJavaDLStrategy.java | 117 +++++------------- .../strategy/ResponsibleStrategyCache.java | 111 +++++++++++++++++ 3 files changed, 145 insertions(+), 84 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/ResponsibleStrategyCache.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java index 9c5bde140d..c68ef3ab5a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java @@ -12,7 +12,6 @@ import org.key_project.prover.rules.RuleSet; public interface ComponentStrategy extends Strategy { - enum StrategyAspect { Cost, Instantiation, Approval; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java index 758f730b1a..2bb30c59d3 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -9,7 +9,6 @@ import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Proof; -import de.uka.ilkd.key.rule.BuiltInRule; import de.uka.ilkd.key.strategy.ComponentStrategy.StrategyAspect; import de.uka.ilkd.key.strategy.feature.AgeFeature; import de.uka.ilkd.key.strategy.feature.MatchedAssumesFeature; @@ -32,7 +31,8 @@ import org.jspecify.annotations.NonNull; -/// Combines a list of strategies into a unified strategy. Theory combination +/// Combines a list of component strategies [ComponentStrategy] into a unified strategy. Theory +/// combination /// is based on the costs computed by each component strategy. Age of the rule /// application is used to ensure that any applicable rule will eventually be /// applied. @@ -45,32 +45,15 @@ public class ModularJavaDLStrategy extends AbstractFeatureStrategy { public static final Name NAME = new Name("Modular JavaDL Strategy"); + /// List of component strategies. Order is not strictly important. private final List strategies = new ArrayList<>(); private final StrategyProperties strategyProperties; - private final Feature reduceCostTillMaxF; + private final Feature reduceInstTillMaxF; private final ArithTermFeatures tf; - private final RuleSetDispatchFeature conflictCostDispatcher; private final Feature totalCost; - // map rulesets to the strategies that participate in their cost computations, instantiation or - // approval decisions - private final Map> costResponsibilityMap = - new LinkedHashMap<>(); - private final Map> instantiationResponsibilityMap = - new LinkedHashMap<>(); - private final Map> approvalResponsibilityMap = - new LinkedHashMap<>(); - - // map rules to the strategies that participate in their cost computations, instantiation or - // approval decisions - private final Map> costRuleToStrategyMap = - new LinkedHashMap<>(); - private final Map> instantiationRuleToStrategyMap = - new LinkedHashMap<>(); - private final Map> approvalRuleToStrategyMap = - new LinkedHashMap<>(); - private final Map nameToStrategyMap = new HashMap<>(); + private final ResponsibleStrategyCache responsibleStrategyCache; public ModularJavaDLStrategy(Proof proof, List componentStrategies, StrategyProperties properties) { @@ -79,22 +62,21 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat this.strategyProperties = (StrategyProperties) properties.clone(); this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); - initializeResponsibilityMap(StrategyAspect.Cost, costResponsibilityMap); - initializeResponsibilityMap(StrategyAspect.Instantiation, instantiationResponsibilityMap); - initializeResponsibilityMap(StrategyAspect.Approval, approvalResponsibilityMap); + responsibleStrategyCache = new ResponsibleStrategyCache(strategies); // if more than one strategy is responsible for a _ruleset_ we need to determine how to // resolve the // competing computations - conflictCostDispatcher = resolveConflicts(); + RuleSetDispatchFeature conflictCostDispatcher = resolveConflicts(); final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); - reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost, - (rule) -> getResponsibleStrategies(rule, costResponsibilityMap, costRuleToStrategyMap)); + Feature reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost, + (rule) -> responsibleStrategyCache.getResponsibleStrategies(rule, strategies, + StrategyAspect.Cost)); reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp, - (rule) -> getResponsibleStrategies(rule, instantiationResponsibilityMap, - instantiationRuleToStrategyMap)); + (rule) -> responsibleStrategyCache.getResponsibleStrategies(rule, strategies, + StrategyAspect.Instantiation)); // the feature for the cost computation totalCost = @@ -102,31 +84,13 @@ public ModularJavaDLStrategy(Proof proof, List componentStrat reduceCostTillMaxF, conflictCostDispatcher, AgeFeature.INSTANCE); } - /** - * Caches the information which strategies are responsible for which ruleset - * - * @param aspect the StrategyAspect for which the cache is created - * @param responsibilityMap the map used as cache for the specified aspect - */ - private void initializeResponsibilityMap(StrategyAspect aspect, - Map> responsibilityMap) { - for (ComponentStrategy strategy : strategies) { - nameToStrategyMap.put(strategy.name(), strategy); - var res = strategy.getResponsibilities(aspect); - for (var rs : res) { - responsibilityMap.computeIfAbsent(rs, k -> new ArrayList<>()).add(strategy); - } - } - } - private record StratAndDispatcher(ComponentStrategy strategy, RuleSetDispatchFeature dispatcher) { } /** * checks for conflicts and resolves known ones (in case an unknown conflict is encountered the - * method fails - * with a runtime exception + * method fails with a runtime exception * * @return the feature implementing the conflict resolution */ @@ -160,26 +124,22 @@ private RuleSetDispatchFeature resolveConflicts() { * @throws IllegalArgumentException if the conflict cannot be resolved */ private void resolveConflict(RuleSetDispatchFeature d, RuleSet rs) { + var folStrat = responsibleStrategyCache.getStrategyByName(JFOLStrategy.NAME); + var intStrat = responsibleStrategyCache.getStrategyByName(IntegerStrategy.NAME); switch (rs.name().toString()) { case "order_terms" -> { - var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); - var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); bindRuleSet(d, "order_terms", ifZero(applyTF("commEqLeft", tf.intF), intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); } case "apply_equations" -> { - var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); - var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); bindRuleSet(d, "apply_equations", ifZero(applyTF(FocusProjection.create(0), tf.intF), intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); } case "apply_equations_andOr" -> { - var folStrat = nameToStrategyMap.get(JFOLStrategy.NAME); - var intStrat = nameToStrategyMap.get(IntegerStrategy.NAME); if (quantifierInstantiatedEnabled()) { bindRuleSet(d, "apply_equations_andOr", ifZero(applyTF(FocusProjection.create(0), tf.intF), @@ -221,8 +181,9 @@ public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { return false; } return reduceTillMax(isApproved, false, Boolean::logicalAnd, - s -> s.isApprovedApp(app, pio, goal), getResponsibleStrategies(app.rule(), - approvalResponsibilityMap, approvalRuleToStrategyMap)); + s -> s.isApprovedApp(app, pio, goal), + responsibleStrategyCache.getResponsibleStrategies(app.rule(), + strategies, StrategyAspect.Approval)); } @Override @@ -230,6 +191,16 @@ public Name name() { return NAME; } + /// A reducer method that accumulates something computed by strategies, e.g., cost or approval + /// (boolean) + /// and stops once the maximum is reached (top cost or `false`). + /// @param the result type to be accumulated + /// @param init initial value + /// @param max the maximal value; once reached, nothing further is computed + /// @param accumulator accumulator function + /// @param mapper maps a strategy to the required value (cost/approval); e.g., + /// [ComponentStrategy#computeCost(RuleApp, PosInOccurrence, ProofGoal)] + /// @param strats the relevant [ComponentStrategy]s for this computation private R reduceTillMax(R init, R max, BiFunction accumulator, Function mapper, LinkedHashSet strats) { for (ComponentStrategy strategy : strats) { @@ -241,32 +212,6 @@ private R reduceTillMax(R init, R max, BiFunction accumulator, return init; } - private LinkedHashSet getResponsibleStrategies(Rule rule, - Map> responsibilityMap, - Map> ruleToStrategyMap) { - LinkedHashSet strats = ruleToStrategyMap.get(rule); - if (strats == null) { - strats = new LinkedHashSet<>(); - if (rule instanceof BuiltInRule bir) { - for (var cs : strategies) { - if (cs.isResponsibleFor(bir)) { - strats.add(cs); - } - } - } else { - var ruleSets = rule.ruleSets(); - while (ruleSets.hasNext()) { - var rs = ruleSets.next(); - List s = responsibilityMap.get(rs); - if (s != null) - strats.addAll(s); - } - } - ruleToStrategyMap.put(rule, strats); - } - return strats; - } - @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, GOAL goal, MutableState mState) { @@ -279,8 +224,14 @@ RuleAppCost compute(ComponentStrategy strategy, RuleApp app, PosInOccurrence pos, Goal goal, MutableState mState); } + /// A [Feature] that computes a [RuleAppCost] as defined in + /// [ModularJavaDLStrategy#reduceInstTillMaxF]. private class ReduceTillMaxFeature implements Feature { + /// A function to get the relevant [RuleAppCost] (i.e., [Feature#computeCost(RuleApp, + /// PosInOccurrence, ProofGoal, MutableState)] or + /// [ComponentStrategy#instantiateApp(RuleApp, PosInOccurrence, Goal, MutableState)]). private final StrategyCostFunction mapper; + /// A function to get the relevant strategies for a [Rule] private final Function> ruleToStrategy; ReduceTillMaxFeature(StrategyCostFunction mapper, diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ResponsibleStrategyCache.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ResponsibleStrategyCache.java new file mode 100644 index 0000000000..0d09a23b5d --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ResponsibleStrategyCache.java @@ -0,0 +1,111 @@ +/* This file is part of KeY - https://key-project.org + * KeY is licensed under the GNU General Public License Version 2 + * SPDX-License-Identifier: GPL-2.0-only */ +package de.uka.ilkd.key.strategy; + +import java.util.*; + +import de.uka.ilkd.key.rule.BuiltInRule; +import de.uka.ilkd.key.strategy.ComponentStrategy.StrategyAspect; + +import org.key_project.logic.Name; +import org.key_project.prover.rules.Rule; +import org.key_project.prover.rules.RuleSet; + +/// A cache for the strategies responsible for a given [Rule] and [RuleSet]. +public class ResponsibleStrategyCache { + // map rulesets to the strategies that participate in their cost computations, instantiation or + // approval decisions + private final Map> costResponsibilityMap = + new LinkedHashMap>(); + private final Map> instantiationResponsibilityMap = + new LinkedHashMap>(); + private final Map> approvalResponsibilityMap = + new LinkedHashMap>(); + // map rules to the strategies that participate in their cost computations, instantiation or + // approval decisions + private final Map> costRuleToStrategyMap = + new LinkedHashMap>(); + private final Map> instantiationRuleToStrategyMap = + new LinkedHashMap>(); + private final Map> approvalRuleToStrategyMap = + new LinkedHashMap>(); + private final Map nameToStrategyMap = + new HashMap(); + + public ResponsibleStrategyCache(List strategies) { + initialize(StrategyAspect.Cost, strategies); + initialize(StrategyAspect.Instantiation, strategies); + initialize(StrategyAspect.Approval, strategies); + } + + /** + * Caches the information which strategies are responsible for which ruleset + * + * @param aspect the StrategyAspect for which the cache is created + * @param strategies list of all component strategies + */ + private void initialize(StrategyAspect aspect, List strategies) { + var map = getResponsibilityMap(aspect); + for (ComponentStrategy strategy : strategies) { + nameToStrategyMap.put(strategy.name(), strategy); + var res = strategy.getResponsibilities(aspect); + for (var rs : res) { + map.computeIfAbsent(rs, k -> new ArrayList<>()).add(strategy); + } + } + } + + /// Returns the map for the given aspect + private Map> getRuleToStrategyMap( + StrategyAspect aspect) { + return switch (aspect) { + case Cost -> costRuleToStrategyMap; + case Instantiation -> instantiationRuleToStrategyMap; + case Approval -> approvalRuleToStrategyMap; + }; + } + + /// Returns the map for the given aspect + private Map> getResponsibilityMap(StrategyAspect aspect) { + return switch (aspect) { + case Cost -> costResponsibilityMap; + case Instantiation -> instantiationResponsibilityMap; + case Approval -> approvalResponsibilityMap; + }; + } + + /// Returns the strategies responsible for the given [Rule] under the given [StrategyAspect]. + public LinkedHashSet getResponsibleStrategies(Rule rule, + List strategies, StrategyAspect aspect) { + var ruleToStrategyMap = getRuleToStrategyMap(aspect); + LinkedHashSet strats = ruleToStrategyMap.get(rule); + if (strats == null) { + strats = new LinkedHashSet<>(); + if (rule instanceof BuiltInRule bir) { + for (var cs : strategies) { + if (cs.isResponsibleFor(bir)) { + strats.add(cs); + } + } + } else { + var ruleSets = rule.ruleSets(); + Map> responsibilityMap = + getResponsibilityMap(aspect); + while (ruleSets.hasNext()) { + var rs = ruleSets.next(); + List s = responsibilityMap.get(rs); + if (s != null) + strats.addAll(s); + } + } + ruleToStrategyMap.put(rule, strats); + } + return strats; + } + + /// Returns the strategy with the given [Name] + public ComponentStrategy getStrategyByName(Name name) { + return nameToStrategyMap.get(name); + } +} From 7ec46d43cc3254afd1e77a6d3b79ca4c8f2bf17d Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 11 Dec 2025 15:12:30 +0100 Subject: [PATCH 61/62] Experiment w/ windows URIs --- .../java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java index a6a2e278f1..3fa3cbec3a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java @@ -60,9 +60,11 @@ private void addInclude(String filename) throws MalformedURLException { // whatsoever filename = filename.replace('\\', File.separatorChar); // Special handling for Linux var path = base.resolve(filename).normalize(); - var uri = URI.create(path.toString()); + String pathString = path.toString().replace(File.separatorChar, '/'); // URIs on Windows + // needs slash + var uri = URI.create(pathString); if (uri.getScheme() == null) { - uri = URI.create("file://" + path); + uri = URI.create("file://" + pathString); } URL url = uri.toURL(); source = RuleSourceFactory.initRuleFile(url); From 2de61fbed85c18c74c265ddbe5996f4a3b5ac575 Mon Sep 17 00:00:00 2001 From: Drodt Date: Thu, 11 Dec 2025 15:21:56 +0100 Subject: [PATCH 62/62] Add third slash to URI again --- .../java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java index 3fa3cbec3a..2de06b53c9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java +++ b/key.core/src/main/java/de/uka/ilkd/key/nparser/builder/IncludeFinder.java @@ -64,7 +64,7 @@ private void addInclude(String filename) throws MalformedURLException { // needs slash var uri = URI.create(pathString); if (uri.getScheme() == null) { - uri = URI.create("file://" + pathString); + uri = URI.create("file:///" + pathString); } URL url = uri.toURL(); source = RuleSourceFactory.initRuleFile(url);