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 db91ec77ac6..515695c1e7a 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; @@ -85,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")); @@ -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", 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 a688d5aa657..724ce2bbe16 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,7 @@ 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; import de.uka.ilkd.key.symbolic_execution.ExecutionVariableExtractor; @@ -4325,7 +4325,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 0c0da931f76..3ba8e6f8571 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/macros/AbstractPropositionalExpansionMacro.java b/key.core/src/main/java/de/uka/ilkd/key/macros/AbstractPropositionalExpansionMacro.java index 3730ae239da..90bd501af19 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 bf7b94b1a03..57d8045383f 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 @@ -137,17 +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; } } - } 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 e3e50418712..b4c5510b9a0 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.ArrayList; import java.util.HashMap; import java.util.List; @@ -129,7 +129,7 @@ public static class File extends KeyAst { /// Returns the includes (possible empty but not null) computed from the underlying parse /// tree. - 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 70881d2dfc6..b758e24d92e 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,14 @@ 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); + } + path = path.getParent(); + 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 040a52fb953..2de06b53c96 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 @@ -44,29 +43,31 @@ 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 - URL path = new URL(base.getProtocol(), base.getHost(), base.getPort(), - basePath + "/" + filename); - source = RuleSourceFactory.initRuleFile(path); - } 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(); + 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:///" + pathString); } + URL url = uri.toURL(); + source = RuleSourceFactory.initRuleFile(url); if (ldt) { includes.putLDT(filename, source); } else { 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 94fa2803998..7ff80ef9a98 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/proof/init/JavaProfile.java b/key.core/src/main/java/de/uka/ilkd/key/proof/init/JavaProfile.java index d91cbbd771c..38538148328 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/proof/io/KeYFile.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/KeYFile.java index a61f882c9b4..45279d29c02 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 5d3a19b03f6..f921f77d6e3 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/java/de/uka/ilkd/key/rule/OneStepSimplifier.java b/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java index 5f5d6cb4986..c04e03ef185 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); @@ -688,7 +689,6 @@ public Set getCapturedTaclets() { return result; } - // ------------------------------------------------------------------------- // inner classes // ------------------------------------------------------------------------- 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 90e67da550e..0da58226050 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,8 +134,21 @@ public void instantiateApp(RuleApp app, PosInOccurrence pio, } while (btManager.backtrack()); } - protected abstract RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, - MutableState mState); + /** + * 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(); + } + + 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 Feature forEach(TermBuffer x, TermGenerator gen, Feature body) { return ForEachCP.create(x, gen, body); @@ -147,22 +163,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); @@ -170,7 +189,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/ComponentStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java new file mode 100644 index 00000000000..c68ef3ab5ab --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ComponentStrategy.java @@ -0,0 +1,28 @@ +/* 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.rule.BuiltInRule; +import de.uka.ilkd.key.strategy.feature.RuleSetDispatchFeature; + +import org.key_project.prover.rules.RuleSet; + +public interface ComponentStrategy extends Strategy { + enum StrategyAspect { + Cost, Instantiation, Approval; + } + + /// The strategy's cost dispatcher. + RuleSetDispatchFeature getDispatcher(StrategyAspect aspect); + + /// The rule sets this strategy is designed to handle. + Set getResponsibilities(StrategyAspect aspect); + + /// 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 new file mode 100644 index 00000000000..2d0680f0089 --- /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 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; +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; +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 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; +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; + +/// 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 implements ComponentStrategy { + 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; + + protected final ArithTermFeatures tf; + protected final FormulaTermFeatures ff; + + 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); + + costComputationDispatcher = setupCostComputationF(); + approvalDispatcher = setupApprovalDispatcher(); + instantiationDispatcher = setupInstantiationF(); + + 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(); + + 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); + } 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 + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return instantiationF.computeCost(app, pio, goal, mState); + } + + @Override + 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 + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null + || approvalDispatcher.get(rs) != null; + } + + @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 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 + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + protected void setupFormulaNormalisation(RuleSetDispatchFeature d) { + 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, "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_orAssoc", + SumFeature.createSum(applyTF("assoc0", ff.clause), + applyTF("assoc1", ff.clause), applyTF("assoc2", ff.literal), longConst(-80))); + + 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)))); + } + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // 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 + // + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + + protected 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())))), + 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)); + } + + @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 new file mode 100644 index 00000000000..85da5d6c654 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -0,0 +1,1040 @@ +/* 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.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; +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; +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.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.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; +import org.key_project.prover.strategy.costbased.termgenerator.SubtermGenerator; + +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 implements ComponentStrategy { + + public static final Name NAME = new Name("Integer Strategy"); + + /// Magic constants + private static final int IN_EQ_SIMP_NON_LIN_COST = 1000; + private static final int POLY_DIVISION_COST = -2250; + + /// 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.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(); + + } + + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; + } + + 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(); + + bindRuleSet(d, "simplify_int", inftyConst()); + + setupArithPrimaryCategories(d); + setupPolySimp(d, numbers); + setupInEqSimp(d, numbers); + + setupDefOpsPrimaryCategories(d); + + bindRuleSet(d, "order_terms", + 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 + // 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 nonLinearArithmeticEnabled; + } + + private boolean arithDefOps() { + return divAndModuloReasoningEnabled; + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return stopAtFirstNonCloseableGoal; + } + + + // ////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////// + // + // 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 isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return !(approvalDispatcher.computeCost(app, pio, goal, + new MutableState()) == TopRuleAppCost.INSTANCE); + + } + + @Override + public 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); + } + + @Override + 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 + public boolean isResponsibleFor(BuiltInRule rule) { + return 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 00000000000..c64563a9c90 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategyFactory.java @@ -0,0 +1,63 @@ +/* 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; + +/// 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
  • " + + "
  • 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/JFOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java new file mode 100644 index 00000000000..fa596fc1f9f --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategy.java @@ -0,0 +1,82 @@ +/* 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.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; + +/// 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 static final Name NAME = new Name("JFOL Strategy"); + + 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); + } + + @Override + public Name name() { + return NAME; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java new file mode 100644 index 00000000000..888b9962685 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java @@ -0,0 +1,67 @@ +/* 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; + +/// 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 = "" + + "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 JFOLStrategy(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/JavaCardDLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategy.java index 5b18237454f..afe6e7bdeaa 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,75 +3,48 @@ * 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.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; -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.rule.QueryExpand; 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; -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.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; +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.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; -/** - * Strategy tailored to be used as long as a java program can be found in the sequent. - */ -public class JavaCardDLStrategy extends AbstractFeatureStrategy { +/// 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 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(); 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; @@ -85,11 +58,9 @@ public class JavaCardDLStrategy extends AbstractFeatureStrategy { private final ArithTermFeatures tf; private final FormulaTermFeatures ff; - private final ValueTermFeature vf; protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) { - super(proof); heapLDT = getServices().getTypeConverter().getHeapLDT(); @@ -97,7 +68,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(); @@ -106,34 +76,36 @@ protected JavaCardDLStrategy(Proof proof, StrategyProperties strategyProperties) costComputationF = setupGlobalF(costComputationDispatcher); instantiationF = setupGlobalF(instantiationDispatcher); 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; } - protected Feature setupGlobalF(Feature dispatcher) { - final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); - - 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; - } - } + @Override + public RuleSetDispatchFeature getDispatcher(StrategyAspect aspect) { + return switch (aspect) { + case StrategyAspect.Cost -> costComputationDispatcher; + case StrategyAspect.Instantiation -> instantiationDispatcher; + case StrategyAspect.Approval -> approvalDispatcher; + }; + } + + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null + || approvalDispatcher.get(rs) != null; + } + protected Feature setupGlobalF(@NonNull Feature dispatcher) { final String queryProp = strategyProperties.getProperty(StrategyProperties.QUERY_OPTIONS_KEY); final Feature queryF; @@ -161,72 +133,13 @@ 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(AutomatedRuleFeature.getInstance(), - NonDuplicateAppFeature.INSTANCE, + return SumFeature.createSum( // splitF, // strengthenConstraints, - AgeFeature.INSTANCE, oneStepSimplificationF, mergeRuleF, // smtF, - methodSpecF, queryF, depSpecF, loopInvF, blockFeature, loopBlockFeature, - loopBlockApplyHeadFeature, ifMatchedF, dispatcher); - } - - private Feature oneStepSimplificationFeature(Feature cost) { - SetRuleFilter filter = new SetRuleFilter(); - filter.addRuleToSet(MiscTools.findOneStepSimplifier(getProof())); - return ConditionalFeature.createConditional(filter, cost); + queryF, depSpecF, dispatcher); } // ////////////////////////////////////////////////////////////////////////// @@ -239,92 +152,34 @@ private Feature oneStepSimplificationFeature(Feature cost) { // ////////////////////////////////////////////////////////////////////////// private RuleSetDispatchFeature setupCostComputationF() { - final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); - final LocSetLDT locSetLDT = getServices().getTypeConverter().getLocSetLDT(); - 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_expression", -100); - bindRuleSet(d, "executeIntegerAssignment", -100); - bindRuleSet(d, "executeDoubleAssignment", -100); - 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()); - - // taclets for special invariant handling - bindRuleSet(d, "loopInvariant", -20000); - 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); - - setUpStringNormalisation(d); - - 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); - - bindRuleSet(d, "confluence_restricted", - ifZero(MatchedAssumesFeature.INSTANCE, DiffFindAndIfFeature.INSTANCE)); - - setupApplyEq(d, numbers); - - bindRuleSet(d, "insert_eq_nonrigid", - 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))); + // 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), @@ -333,9 +188,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))); @@ -345,79 +198,11 @@ 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))); - - 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) - .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); */ - boolean programsToRight = true; // XXX - - 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); @@ -434,20 +219,10 @@ 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 () ); */ - // 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))); @@ -460,52 +235,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); - setupArithPrimaryCategories(d); - setupPolySimp(d, numbers); - setupInEqSimp(d, numbers); - - setupDefOpsPrimaryCategories(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()); - } - - // 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 @@ -583,108 +316,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), - 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 = @@ -713,47 +344,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)); - } - - 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); @@ -783,1110 +373,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, IntegerLDT numbers) { - 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(applyTF(FocusProjection.create(0), tf.intF), - 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), 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))); - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // 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"), ifZero(applyTF(left, tf.intF), - add(applyTF(left, tf.nonNegOrNonCoeffMonomial), applyTF(right, tf.polynomial), - MonomialsSmallerThanFeature.create(right, left, numbers)), - 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()); - } - } - - // ////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////// - // - // 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(); - 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 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))); - - } - // ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// // @@ -1907,49 +393,17 @@ protected Feature setupApprovalF() { depSpecF = ConditionalFeature.createConditional(depFilter, inftyConst()); } - return add(NonDuplicateAppFeature.INSTANCE, depSpecF); + return depSpecF; // add(NonDuplicateAppFeature.INSTANCE, depSpecF); } 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); setupClassAxiomApproval(d); - setupQuantifierInstantiationApproval(d); - setupSplittingApproval(d); bindRuleSet(d, "apply_select_eq", add(isInstantiated("s"), isInstantiated("t1"), @@ -1962,12 +416,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; } @@ -1995,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()); @@ -2021,16 +469,6 @@ private RuleSetDispatchFeature setupInstantiationF() { enableInstantiate(); final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); - - setupQuantifierInstantiation(d); - - setupArithPrimaryCategories(d); - setupDefOpsPrimaryCategories(d); - - setupInstantiationWithoutRetry(d); - - setupInEqSimpInstantiation(d); - setClassAxiomInstantiation(d); disableInstantiate(); @@ -2053,18 +491,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() { @@ -2085,10 +511,10 @@ private void setupInstantiationWithoutRetry(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); @@ -2119,7 +545,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(); @@ -2143,4 +569,9 @@ public boolean isStopAtFirstNonCloseableGoal() { return strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) .equals(StrategyProperties.STOPMODE_NONCLOSE); } + + @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/JavaCardDLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JavaCardDLStrategyFactory.java index a828f7ef9a0..873eb4757b5 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,12 +13,9 @@ import org.key_project.logic.Name; -import org.jspecify.annotations.NonNull; - -/** - * - * @author Kai Wallisch - */ +/// Factory for [JavaCardDLStrategy]. Additionally, handles all strategy settings +/// relevant to it. +/// @author Kai Wallisch public class JavaCardDLStrategyFactory implements StrategyFactory { /** @@ -29,13 +23,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,
" @@ -67,71 +54,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 = @@ -189,44 +111,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 = "" - + "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
" @@ -257,29 +141,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", @@ -300,61 +161,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", @@ -382,31 +188,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, - 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", @@ -429,32 +210,8 @@ 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) { + public JavaCardDLStrategy create(Proof proof, StrategyProperties strategyProperties) { return new JavaCardDLStrategy(proof, strategyProperties); } @@ -466,25 +223,14 @@ public Name name() { @Override public StrategySettingsDefinition getSettingsDefinition() { // Properties - final OneOfStrategyPropertyDefinition stopAt = getStopAt(); 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 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, - loopTreatment, blockTreatment, methodTreatment, mergePointStatementTreatment, - dependencyContracts, queryTreatment, arithmeticTreatment, quantifierTreatment, - classAxiom, autoInduction, userOptions); + return new StrategySettingsDefinition("Java DL Options", ossUsage, proofSplitting, + 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 new file mode 100644 index 00000000000..2bb30c59d34 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategy.java @@ -0,0 +1,256 @@ +/* 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 java.util.function.BiFunction; +import java.util.function.Function; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; +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; +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; +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; +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.key_project.prover.strategy.costbased.feature.AutomatedRuleFeature; +import org.key_project.prover.strategy.costbased.feature.Feature; + +import org.jspecify.annotations.NonNull; + +/// 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. +/// +/// 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"); + + /// List of component strategies. Order is not strictly important. + private final List strategies = new ArrayList<>(); + private final StrategyProperties strategyProperties; + + private final Feature reduceInstTillMaxF; + private final ArithTermFeatures tf; + private final Feature totalCost; + + private final ResponsibleStrategyCache responsibleStrategyCache; + + public ModularJavaDLStrategy(Proof proof, List componentStrategies, + StrategyProperties properties) { + super(proof); + strategies.addAll(componentStrategies); + this.strategyProperties = (StrategyProperties) properties.clone(); + this.tf = new ArithTermFeatures(getServices().getTypeConverter().getIntegerLDT()); + + responsibleStrategyCache = new ResponsibleStrategyCache(strategies); + + // if more than one strategy is responsible for a _ruleset_ we need to determine how to + // resolve the + // competing computations + RuleSetDispatchFeature conflictCostDispatcher = resolveConflicts(); + + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + Feature reduceCostTillMaxF = new ReduceTillMaxFeature(Feature::computeCost, + (rule) -> responsibleStrategyCache.getResponsibleStrategies(rule, strategies, + StrategyAspect.Cost)); + + reduceInstTillMaxF = new ReduceTillMaxFeature(ComponentStrategy::instantiateApp, + (rule) -> responsibleStrategyCache.getResponsibleStrategies(rule, strategies, + StrategyAspect.Instantiation)); + + // the feature for the cost computation + totalCost = + add(AutomatedRuleFeature.getInstance(), ifMatchedF, NonDuplicateAppFeature.INSTANCE, + reduceCostTillMaxF, conflictCostDispatcher, AgeFeature.INSTANCE); + } + + 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 = + strategies.stream() + .map(s -> new StratAndDispatcher(s, s.getDispatcher(StrategyAspect.Cost))) + .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.name()); + } + } + for (var e : map.entrySet()) { + if (e.getValue().size() > 1) { + resolveConflict(dis, e.getKey()); + } + } + 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) { + var folStrat = responsibleStrategyCache.getStrategyByName(JFOLStrategy.NAME); + var intStrat = responsibleStrategyCache.getStrategyByName(IntegerStrategy.NAME); + switch (rs.name().toString()) { + case "order_terms" -> { + bindRuleSet(d, "order_terms", + ifZero(applyTF("commEqLeft", tf.intF), + intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), + folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); + } + case "apply_equations" -> { + 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" -> { + if (quantifierInstantiatedEnabled()) { + bindRuleSet(d, "apply_equations_andOr", + ifZero(applyTF(FocusProjection.create(0), tf.intF), + intStrat.getDispatcher(StrategyAspect.Cost).remove(rs), + folStrat.getDispatcher(StrategyAspect.Cost).remove(rs))); + } else { + bindRuleSet(d, "apply_equations_andOr", inftyConst()); + } + } + default -> throw new IllegalArgumentException("No resolution defined for " + rs); + } + } + + @Override + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + enableInstantiate(); + final Feature ifMatchedF = ifZero(MatchedAssumesFeature.INSTANCE, longConst(+1)); + 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); + } + + @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) { + 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), + responsibleStrategyCache.getResponsibleStrategies(app.rule(), + strategies, StrategyAspect.Approval)); + } + + @Override + 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) { + 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 totalCost.computeCost(app, pos, goal, mState); + } + + @FunctionalInterface + private interface StrategyCostFunction { + 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, + Function> ruleToStrategy) { + this.mapper = mapper; + this.ruleToStrategy = ruleToStrategy; + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { + return reduceTillMax(NumberRuleAppCost.getZeroCost(), TopRuleAppCost.INSTANCE, + RuleAppCost::add, s -> mapper.compute(s, app, pos, (Goal) goal, mState), + ruleToStrategy.apply(app.rule())); + } + } + + private boolean quantifierInstantiatedEnabled() { + return !StrategyProperties.QUANTIFIERS_NONE + .equals(strategyProperties.getProperty(StrategyProperties.QUANTIFIERS_OPTIONS_KEY)); + } +} 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 00000000000..a356f1b00e2 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ModularJavaDLStrategyFactory.java @@ -0,0 +1,155 @@ +/* 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; + +/// Creates a [ModularJavaDLStrategy] and handles strategy settings relevant to it. +public class ModularJavaDLStrategyFactory implements StrategyFactory { + private final List componentFactories = + Arrays.asList(new JFOLStrategyFactory(), + new IntegerStrategyFactory(), new SymExStrategyFactory(), 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 -> (ComponentStrategy) 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("JavaDL Options", properties); + } +} 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 00000000000..0d09a23b5d7 --- /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); + } +} 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 1afbc52f4ac..bb9198ffa63 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/Strategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/Strategy.java index 04d24c004b0..6d1c1fd1900 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; @@ -18,6 +19,7 @@ import org.jspecify.annotations.NonNull; + /** * Generic interface for evaluating the cost of a RuleApp with regard to a specific strategy */ @@ -79,4 +81,12 @@ static void updateStrategySettings(Proof proof, StrategyProperties p) { proof.setActiveStrategy(strategy); } + + 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 new file mode 100644 index 00000000000..06600a5cdbb --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategy.java @@ -0,0 +1,211 @@ +/* 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.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; +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 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.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; + +/// Strategy for string related rules. +/// +/// Do not create directly; use [StringStrategyFactory] instead. +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, + /// 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); + } + + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null; + } + + 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 true; + /* + * NonDuplicateAppFeature.INSTANCE.computeCost(app, pio, goal, + * new MutableState()) != TopRuleAppCost.INSTANCE; + */ + } + + @Override + public 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); + } + + @Override + 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 + public boolean isResponsibleFor(BuiltInRule rule) { + return false; + } +} 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 00000000000..9d1a4b68139 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StringStrategyFactory.java @@ -0,0 +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.strategy; + +import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.strategy.definition.StrategySettingsDefinition; + +import org.key_project.logic.Name; + +/// Creates [StringStrategy]. +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/SymExStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java new file mode 100644 index 00000000000..d4c55df36d5 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategy.java @@ -0,0 +1,279 @@ +/* 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.HashSet; +import java.util.Set; + +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; +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.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.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; + +/// Strategy for symbolic execution rules. +/// +/// Do not create directly. Use [SymExStrategyFactory] instead. +public class SymExStrategy extends AbstractFeatureStrategy implements ComponentStrategy { + public static final Name NAME = new Name("SymExStrategy"); + + private final FormulaTermFeatures ff; + + private final StrategyProperties strategyProperties; + + private final RuleSetDispatchFeature costComputationDispatcher; + private final Feature costComputationF; + 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(); + instantiationDispatcher = new RuleSetDispatchFeature(); + + costComputationF = setupGlobalF(costComputationDispatcher); + instantiationF = setupGlobalF(instantiationDispatcher); + } + + @Override + public boolean isResponsibleFor(RuleSet rs) { + return costComputationDispatcher.get(rs) != null || instantiationDispatcher.get(rs) != null; + } + + @Override + 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; + case StrategyAspect.Instantiation -> instantiationDispatcher; + default -> null; + }; + } + + + 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; + } + } + + Feature loopInvF; + final String loopProp = strategyProperties.getProperty(StrategyProperties.LOOP_OPTIONS_KEY); + if (loopProp.equals(StrategyProperties.LOOP_INVARIANT)) { + loopInvF = loopInvFeature(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() { + 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); + + bindRuleSet(d, "simplify_java", -4500); + + bindRuleSet(d, "executeIntegerAssignment", -100); + bindRuleSet(d, "executeDoubleAssignment", -100); + + final Feature findDepthFeature = + FindDepthFeature.getInstance(); + bindRuleSet(d, "concrete_java", + add(longConst(-11000), + ScaleFeature.createScaled(findDepthFeature, 10.0))); + + // 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)); + + 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 + public RuleAppCost instantiateApp(RuleApp app, PosInOccurrence pio, Goal goal, + MutableState mState) { + return instantiationF.computeCost(app, pio, goal, mState); + } + + @Override + public boolean isStopAtFirstNonCloseableGoal() { + return false; + } + + @Override + public boolean isApprovedApp(RuleApp app, PosInOccurrence pio, Goal goal) { + return true; + } + + @Override + public Name name() { + return NAME; + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, GOAL goal, MutableState mState) { + return costComputationF.computeCost(app, pos, goal, mState); + } + + @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; + } +} 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 00000000000..7e7ab19dab7 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/SymExStrategyFactory.java @@ -0,0 +1,138 @@ +/* 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; + +/// 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:
" + + "
  • 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, 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() { + 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 + public Name name() { + return SymExStrategy.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 080b987c5eb..f96a252ecce 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; 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 936b503ba11..72480202f93 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; 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 2040af28e8f..4b41c75ff2b 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,6 +34,10 @@ public class RuleSetDispatchFeature implements Feature { private final Map rulesetToFeature = new LinkedHashMap<>(); + public Set ruleSets() { + return rulesetToFeature.keySet(); + } + @Override public > RuleAppCost computeCost(RuleApp app, PosInOccurrence pos, Goal goal, @@ -95,4 +100,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); + } } 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 457218bd684..cafa348a2cc 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); } 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/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 00000000000..c605ac1da86 --- /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 73337d3d4d9..4e76e26fba3 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/javaRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key index d9633b05f09..ca7fbba2b5c 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,14 +330,13 @@ // ---------- rules for array store ---------------// - array_self_reference { \schemaVar \term Heap heapSV; \assumes(wellFormed(heapSV) ==> array = null) \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 @@ -348,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 { @@ -357,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" }; */ @@ -376,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" }; @@ -1341,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" }; @@ -1522,7 +1521,7 @@ insert_constant_value { \find(#cv) \replacewith(#constantvalue(#cv)) - \heuristics(concrete) + \heuristics(concrete_java) }; // ------------------------------------------------------------------------ @@ -4055,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" }; @@ -4064,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" }; @@ -4073,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" }; @@ -4082,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" }; @@ -4091,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)" }; @@ -4101,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" }; @@ -4111,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 { @@ -4120,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/ldt.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ldt.key index d54f2527f00..e5d9b942ccd 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,16 +16,17 @@ ruleSetsDeclarations, soundDefaultContracts, boolean, - integerHeader, + "./integer/integerHeader.key", + "./integer/javaIntegerHeader.key", javaHeader, - floatHeader, + "./float/floatHeader.key", heap, - locSets, - permission, + "./locset/locSets.key", + "./permission/permission.key", reach, - seq, + "./sequence/seq.key", map, freeADT, wellfound, - charListHeader, + "./string/charListHeader.key", 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/ruleSetsDeclarations.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/ruleSetsDeclarations.key index 8141bd44ac4..1be9befdfbd 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; 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 90e8d1940cc..f5a06be72b4 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 propRule; -\include firstOrderRules; +\include "./classicalLogic/propRule.key"; +\include "./classicalLogic/firstOrderRules.key"; \include ifThenElseRules; -\include formulaNormalisationRules; +\include "./classicalLogic/formulaNormalisationRules.key"; \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.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 floatRulesCommon; -\include floatRules, - floatRulesVerifyNormal, - 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 locSetsRules; // must go before heap +\include "./locset/locSetsRules.key"; // must go before heap \include heapRules; -\include permissionRules; +\include "./permission/permissionRules.key"; \include reachRules; -\include seqCoreRules, seqRules; -\include seqPerm; -\include 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 integerAssignment2UpdateRules; -\include floatAssignment2UpdateRules; -\include 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 charListRules; -\include regExTheory; // TODO: fix rules and uncomment +\include "./string/charListRules.key"; +\include "./string/regExTheory.key"; // rules for information flow verification -\include seqEq; +\include "./sequence/seqEq.key"; \include infFlow; // size rules for maps \include mapSize; // rules for well-definedness -\include wd; +\include "./wellDefined/wd.key"; // 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 5bba4dd7fe9..a863637be54 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 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 301292fd168..9af8750195a 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(); 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 a95305f3dbf..212869c6f5b 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) ========================================= 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 8f0bd03be28..c0ca67ba9b3 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 fa599589f7e..9a8c547a060 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(); } diff --git a/key.ui/examples/redux/arrays/Arrays.copyOf.float.key b/key.ui/examples/redux/arrays/Arrays.copyOf.float.key index 71d0ba17029..9c3968be390 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 85111ad87fa..371efe3289c 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 eb36cfd2209..bb60623d333 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 3d50ab9ea6a..5e5ef659672 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