From 9692df45a77d15f4a54b01c3ff8d448fd0da3661 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Tue, 14 Jul 2026 16:46:01 +0200 Subject: [PATCH 01/15] Improve heap simplification --- .../key/macros/HeapSimplificationMacro.java | 3 + .../uka/ilkd/key/rule/OneStepSimplifier.java | 4 +- .../DropEffectlessElementariesCondition.java | 6 +- .../DropEffectlessStoresCondition.java | 16 ++-- .../ilkd/key/rule/inst/SVInstantiations.java | 12 ++- .../ilkd/key/strategy/JavaCardDLStrategy.java | 2 + .../de/uka/ilkd/key/proof/rules/heapRules.key | 89 ++++++++++++++++++- .../key/proof/rules/ruleSetsDeclarations.key | 2 + 8 files changed, 118 insertions(+), 16 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/HeapSimplificationMacro.java b/key.core/src/main/java/de/uka/ilkd/key/macros/HeapSimplificationMacro.java index 4df46543999..7e1c7798810 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/HeapSimplificationMacro.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/HeapSimplificationMacro.java @@ -43,6 +43,9 @@ public String getDescription() { "selectCreatedOfStore", "selectCreatedOfCreate", "selectCreatedOfAnon", "selectCreatedOfMemset", + "selectOfStoreSameLoc", "selectOfCreateReduce", "simplifySelectOfStoreDiffFields", + "simplifySelectOfStoreDiffObjects", + "dismissNonSelectedField", "dismissNonSelectedFieldEQ", "replaceKnownSelect", "dropEffectlessStores", "memsetEmpty", "selectCreatedOfAnonAsFormula", 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 b7ac8966dab..c981dc244dd 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 @@ -79,11 +79,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 = ImmutableList.nil() - .append("concrete").append("concrete_java").append("update_elim") + .append("concrete").append("simplify_select_elim_store").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, false, true, true, true, false }; + private static final boolean[] bottomUp = { false, false, false, false, true, true, true, false }; // OSS is shared per proof and runs concurrently on every parallel-prover worker. Its two caches // are PURE (the value is a function of the key: "does this formula simplify?" / "this term is // irreducible"), so eviction order is irrelevant to the result and a striped (lower-contention) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessElementariesCondition.java b/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessElementariesCondition.java index 93a24a23f1d..475dae96a09 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessElementariesCondition.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessElementariesCondition.java @@ -162,9 +162,9 @@ public MatchResultInfo check(SchemaVariable var, SyntaxElement instCandidate, LogicServices services) { SVInstantiations svInst = (SVInstantiations) mc.getInstantiations(); - JTerm uInst = (JTerm) svInst.getInstantiation(u); - JTerm xInst = (JTerm) svInst.getInstantiation(x); - JTerm resultInst = (JTerm) svInst.getInstantiation(result); + JTerm uInst = svInst.getInstantiation(u); + JTerm xInst = svInst.getInstantiation(x); + JTerm resultInst = svInst.getInstantiation(result); if (uInst == null || xInst == null) { return mc; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessStoresCondition.java b/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessStoresCondition.java index ee88e8d6f8d..4fb1658f893 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessStoresCondition.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/conditions/DropEffectlessStoresCondition.java @@ -3,6 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.rule.conditions; +import java.util.LinkedHashSet; +import java.util.Set; + import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.ldt.HeapLDT; import de.uka.ilkd.key.logic.JTerm; @@ -16,8 +19,6 @@ import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.VariableCondition; import org.key_project.prover.rules.instantiation.MatchResultInfo; -import org.key_project.util.collection.DefaultImmutableSet; -import org.key_project.util.collection.ImmutableSet; import org.key_project.util.collection.Pair; @@ -38,16 +39,18 @@ public DropEffectlessStoresCondition(TermSV h, TermSV o, TermSV f, TermSV x, Ter private static JTerm dropEffectlessStoresHelper(JTerm heapTerm, TermServices services, - ImmutableSet> overwrittenLocs, Function store) { + Set> overwrittenLocs, Function store) { if (heapTerm.op() == store) { final JTerm subHeapTerm = heapTerm.sub(0); final JTerm objTerm = heapTerm.sub(1); final JTerm fieldTerm = heapTerm.sub(2); final JTerm valueTerm = heapTerm.sub(3); final Pair loc = new Pair<>(objTerm, fieldTerm); + final boolean overwrittenAbove = overwrittenLocs.contains(loc); + overwrittenLocs.add(loc); final JTerm newSubHeapTerm = - dropEffectlessStoresHelper(subHeapTerm, services, overwrittenLocs.add(loc), store); - if (overwrittenLocs.contains(loc)) { + dropEffectlessStoresHelper(subHeapTerm, services, overwrittenLocs, store); + if (overwrittenAbove) { return newSubHeapTerm == null ? subHeapTerm : newSubHeapTerm; } else { return newSubHeapTerm == null ? null @@ -63,8 +66,7 @@ private static JTerm dropEffectlessStoresHelper(JTerm heapTerm, TermServices ser private static JTerm dropEffectlessStores(JTerm t, Services services) { HeapLDT heapLDT = services.getTypeConverter().getHeapLDT(); assert t.sort() == heapLDT.targetSort(); - return dropEffectlessStoresHelper(t, services, DefaultImmutableSet.nil(), - heapLDT.getStore()); + return dropEffectlessStoresHelper(t, services, new LinkedHashSet<>(), heapLDT.getStore()); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java index eef30f81e0e..879d8fad9c3 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/inst/SVInstantiations.java @@ -81,6 +81,9 @@ public boolean canStandFor(ProgramElement pe, Services services) { /** additional conditions for the generic sorts */ private final ImmutableList genericSortConditions; + private ContextStatementBlockInstantiation contextInstantiationCache; + private boolean contextInstantiationCached; + /** creates a new SVInstantiations object with an empty map */ private SVInstantiations() { genericSortConditions = ImmutableList.nil(); @@ -431,8 +434,13 @@ public SVInstantiations clearUpdateContext() { * returns the instantiation entry for the context "schema variable" or null if non such exists */ public ContextStatementBlockInstantiation getContextInstantiation() { - final InstantiationEntry entry = getInstantiationEntry(CONTEXTSV); - return entry == null ? null : (ContextStatementBlockInstantiation) entry.getInstantiation(); + if (!contextInstantiationCached) { + final InstantiationEntry entry = getInstantiationEntry(CONTEXTSV); + contextInstantiationCache = entry == null ? null + : (ContextStatementBlockInstantiation) entry.getInstantiation(); + contextInstantiationCached = true; + } + return contextInstantiationCache; } /** 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 afe6e7bdeaa..d9340d0daf2 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 @@ -298,6 +298,8 @@ private void setupSelectSimplification(final RuleSetDispatchFeature d) { applyTF(sub(FocusProjection.INSTANCE, 0), not(SimplifiedSelectTermFeature.create(heapLDT))), longConst(-5600))); + bindRuleSet(d, "simplify_select_concrete", longConst(-6000)); + bindRuleSet(d, "simplify_select_elim_store", longConst(-7000)); bindRuleSet(d, "apply_auxiliary_eq", // replace skolem constant by it's computed value add(isSelectSkolemConstantTerm("t1"), longConst(-5500))); diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key index 36377431eb0..58ff9516d75 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key @@ -649,6 +649,91 @@ // lemmata for some common cases // -------------------------------------------------------------------------- + \lemma + selectOfStoreSameLoc { + \schemaVar \term Heap h; + \schemaVar \term Object o; + \schemaVar \term Field f; + \schemaVar \term alpha x; + + \find(select<[beta]>(store(h, o, f, x), o, f)) + + \replacewith(\if(f != java.lang.Object::#$created) + \then((beta)x) + \else(select<[beta]>(h, o, f))) + \heuristics(simplify_select_concrete) + }; + + \lemma + selectOfCreateReduce { + \schemaVar \term Heap h; + \schemaVar \term Object o; + \schemaVar \term Field f; + + \assumes(==> o = null) + \find(select<[beta]>(create(h, o), o, f)) + + (permissions:off) { + \replacewith(\if(f = java.lang.Object::#$created) + \then((beta)TRUE) + \else(select<[beta]>(h, o, f))) + }; + (permissions:on) { + \replacewith(\if(f = java.lang.Object::#$created) \then((beta)TRUE) \else(defaultValue<[beta]>)) + } + \heuristics(simplify_select_concrete) + }; + +\lemma + selectOfCreateReduceConcrete { + \schemaVar \term Heap h; + \schemaVar \term Object o; + \schemaVar \term Field f; + + \assumes(==> o = null) + \find(select<[beta]>(create(h, o), o, java.lang.Object::#$created)) + + (permissions:off) { + \replacewith((beta)TRUE) + }; + (permissions:on) { + \replacewith((beta)TRUE) + } + \heuristics(concrete) + }; + + + simplifySelectOfStoreDiffObjects { + \schemaVar \term Heap h; + \schemaVar \term Object o, o2; + \schemaVar \term Field f; + \schemaVar \term alpha x; + \schemaVar \term beta sk; + + \assumes(==> o = o2) + \find(select<[beta]>(store(h, o, f, x), o2, f)) + \sameUpdateLevel + \replacewith(select<[beta]>(h, o2, f)) + + \heuristics(simplify_select_elim_store) + }; + + simplifySelectOfMemsetWithArrayRangeDiffArray { + \schemaVar \term Heap h; + \schemaVar \term LocSet s; + \schemaVar \term any x; + \schemaVar \term Object o, o2; + \schemaVar \term int low, high; + \schemaVar \term Field f; + \schemaVar \term beta sk; + + \assumes(==> o = o2) + \find(select<[beta]>(memset(h, arrayRange(o, low, high), x), o2, f)) + \sameUpdateLevel + \replacewith(select<[beta]>(h, o2, f)) + \heuristics(simplify_select_elim_store) + }; + dismissNonSelectedField { \schemaVar \term Heap h; \schemaVar \term Object o, u; @@ -661,7 +746,7 @@ \replacewith(select<[alpha]>(h, u, f2)) - \heuristics(simplify) + \heuristics(simplify_select_elim_store) }; dismissNonSelectedFieldEQ { @@ -676,7 +761,7 @@ \replacewith(select<[alpha]>(h, u, f2)) - \heuristics(simplify) + \heuristics(simplify_select_elim_store) }; dropEffectlessStores { 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 b03574d0128..cef165bbca2 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 @@ -266,6 +266,8 @@ // heap simplification pull_out_select; simplify_select; + simplify_select_elim_store; + simplify_select_concrete; apply_select_eq; apply_auxiliary_eq; hide_auxiliary_eq; From 5ea55a9a3f9766741b3f17d810c66e4f252bf4a9 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Tue, 14 Jul 2026 21:29:17 +0200 Subject: [PATCH 02/15] added taclet soundness proofs (4/5, the fifth uses a varcond that is not supported by the taclet soundness po generator) --- .../de/uka/ilkd/key/proof/rules/heapRules.key | 2 + .../de/uka/ilkd/key/nparser/taclets.old.txt | 37 ++++++- .../heap/Taclet_selectOfCreateReduce.proof | 102 ++++++++++++++++++ .../Taclet_selectOfCreateReduceConcrete.proof | 95 ++++++++++++++++ .../heap/Taclet_selectOfStoreSameLoc.proof | 96 +++++++++++++++++ ...electOfMemsetWithArrayRangeDiffArray.proof | 100 +++++++++++++++++ ...let_simplifySelectOfStoreDiffObjects.proof | 100 +++++++++++++++++ 7 files changed, 529 insertions(+), 3 deletions(-) create mode 100644 key.core/tacletProofs/heap/Taclet_selectOfCreateReduce.proof create mode 100644 key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof create mode 100644 key.core/tacletProofs/heap/Taclet_selectOfStoreSameLoc.proof create mode 100644 key.core/tacletProofs/heap/Taclet_simplifySelectOfMemsetWithArrayRangeDiffArray.proof create mode 100644 key.core/tacletProofs/heap/Taclet_simplifySelectOfStoreDiffObjects.proof diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key index 58ff9516d75..d292fdbfc93 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key @@ -703,6 +703,7 @@ }; + \lemma simplifySelectOfStoreDiffObjects { \schemaVar \term Heap h; \schemaVar \term Object o, o2; @@ -718,6 +719,7 @@ \heuristics(simplify_select_elim_store) }; + \lemma simplifySelectOfMemsetWithArrayRangeDiffArray { \schemaVar \term Heap h; \schemaVar \term LocSet s; 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 07ac654e5e6..153e55ee7f8 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: Thu Jul 09 09:36:44 CEST 2026 +# Date: Tue Jul 21 09:39:34 CEST 2026 == abortJavaCardTransactionAPI (abortJavaCardTransactionAPI) ========================================= abortJavaCardTransactionAPI { @@ -5820,7 +5820,7 @@ dismissNonSelectedField { \find(select<[alpha]>(store(h,o,f1,x),u,f2)) \varcond(\differentFields (f1 (Field term), f2 (Field term))) \replacewith(select<[alpha]>(h,u,f2)) -\heuristics(simplify) +\heuristics(simplify_select_elim_store) Choices: programRules:Java} ----------------------------------------------------- == dismissNonSelectedFieldEQ (dismissNonSelectedFieldEQ) ========================================= @@ -5829,7 +5829,7 @@ dismissNonSelectedFieldEQ { \find(select<[alpha]>(EQ,u,f2)) \sameUpdateLevel\varcond(\differentFields (f1 (Field term), f2 (Field term))) \replacewith(select<[alpha]>(h,u,f2)) -\heuristics(simplify) +\heuristics(simplify_select_elim_store) Choices: programRules:Java} ----------------------------------------------------- == distr_existsAnd1 (distr_existsAnd1) ========================================= @@ -15910,6 +15910,14 @@ selectOfCreateEQ { \heuristics(simplify_heap_high_costs) Choices: programRules:Java} ----------------------------------------------------- +== selectOfCreateReduce (selectOfCreateReduce) ========================================= +selectOfCreateReduce { +\assumes ([]==>[equals(o,null)]) +\find(select<[beta]>(create(h,o),o,f)) +\sameUpdateLevel\replacewith(if-then-else(equals(f,java.lang.Object::#$created),cast<[beta]>(TRUE),select<[beta]>(h,o,f))) +\heuristics(simplify_select_concrete) +Choices: programRules:Java} +----------------------------------------------------- == selectOfMemset (selectOfMemset) ========================================= selectOfMemset { \find(select<[beta]>(memset(h,s,x),o,f)) @@ -15940,6 +15948,13 @@ selectOfStoreEQ { \heuristics(simplify_heap_high_costs) Choices: programRules:Java} ----------------------------------------------------- +== selectOfStoreSameLoc (selectOfStoreSameLoc) ========================================= +selectOfStoreSameLoc { +\find(select<[beta]>(store(h,o,f,x),o,f)) +\replacewith(if-then-else(not(equals(f,java.lang.Object::#$created)),cast<[beta]>(x),select<[beta]>(h,o,f))) +\heuristics(simplify_select_concrete) +Choices: programRules:Java} +----------------------------------------------------- == seqConcatUnfoldLeft (seqConcatUnfold) ========================================= seqConcatUnfoldLeft { \find(#allmodal ((modal operator))|{{ .. @@ -16562,6 +16577,14 @@ Choices: programRules:Java}] \replacewith([equals(if-then-else(and(elementOf(o,f \heuristics(simplify_select) Choices: programRules:Java} ----------------------------------------------------- +== simplifySelectOfMemsetWithArrayRangeDiffArray (simplifySelectOfMemsetWithArrayRangeDiffArray) ========================================= +simplifySelectOfMemsetWithArrayRangeDiffArray { +\assumes ([]==>[equals(o,o2)]) +\find(select<[beta]>(memset(h,arrayRange(o,low,high),x),o2,f)) +\sameUpdateLevel\replacewith(select<[beta]>(h,o2,f)) +\heuristics(simplify_select_elim_store) +Choices: programRules:Java} +----------------------------------------------------- == simplifySelectOfStore (simplifySelectOfStore) ========================================= simplifySelectOfStore { \find(equals(select<[beta]>(store(h,o,f,x),o2,f2),sk)==>) @@ -16573,6 +16596,14 @@ Choices: programRules:Java}] \replacewith([equals(if-then-else(and(and(equals(o, \heuristics(simplify_select) Choices: programRules:Java} ----------------------------------------------------- +== simplifySelectOfStoreDiffObjects (simplifySelectOfStoreDiffObjects) ========================================= +simplifySelectOfStoreDiffObjects { +\assumes ([]==>[equals(o,o2)]) +\find(select<[beta]>(store(h,o,f,x),o2,f)) +\sameUpdateLevel\replacewith(select<[beta]>(h,o2,f)) +\heuristics(simplify_select_elim_store) +Choices: programRules:Java} +----------------------------------------------------- == simplifySelectOfStoreEQ (simplifySelectOfStoreEQ) ========================================= simplifySelectOfStoreEQ { \assumes ([equals(store(h,o,f,x),EQ)]==>[]) diff --git a/key.core/tacletProofs/heap/Taclet_selectOfCreateReduce.proof b/key.core/tacletProofs/heap/Taclet_selectOfCreateReduce.proof new file mode 100644 index 00000000000..1ecf24edf87 --- /dev/null +++ b/key.core/tacletProofs/heap/Taclet_selectOfCreateReduce.proof @@ -0,0 +1,102 @@ +\profile "Java Profile"; + +\settings { + "Choice" : { + "JavaCard" : "JavaCard:on", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:ban", + "sequences" : "sequences:on" + }, + "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", + "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_ON", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", + "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_FULL", + "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" + } + } +} + + + +\proofObligation +// +{ + "class" : "de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput", + "name" : "selectOfCreateReduce" +} + +\proof { +(keyLog "0" (keyUser "bubel" ) (keyVersion "40f2ff40876dc6765d47e8d8cd9ca970f14235f7")) + +(autoModeTime "28") + +(branch "dummy ID" +(rule "impRight" (formula "1")) +(rule "andLeft" (formula "1")) +(rule "notLeft" (formula "2")) +(rule "notLeft" (formula "1")) +(rule "eqSymm" (formula "2")) +(rule "eqSymm" (formula "1")) +(rule "pullOutSelect" (formula "2") (term "2,0") (inst "selectSK=f_f_0:beta")) +(rule "pullOutSelect" (formula "3") (term "1") (inst "selectSK=f_f_1:beta")) +(rule "applyEq" (formula "3") (term "1") (ifseqformula "1")) +(rule "simplifySelectOfCreate" (formula "1")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "5"))) +(rule "applyEq" (formula "1") (term "2,0") (ifseqformula "2")) +(rule "close" (formula "4") (ifseqformula "1")) +) +} diff --git a/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof b/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof new file mode 100644 index 00000000000..acf64f07641 --- /dev/null +++ b/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof @@ -0,0 +1,95 @@ +\profile "Java Profile"; + +\settings { + "Choice" : { + "JavaCard" : "JavaCard:on", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:ban", + "sequences" : "sequences:on" + }, + "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", + "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_ON", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", + "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_FULL", + "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" + } + } +} + + + +\proofObligation +// +{ + "class" : "de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput", + "name" : "selectOfCreateReduceConcrete" +} + +\proof { +(keyLog "0" (keyUser "bubel" ) (keyVersion "40f2ff40876dc6765d47e8d8cd9ca970f14235f7")) + +(autoModeTime "17") + +(branch "dummy ID" + (builtin "One Step Simplification" (formula "1")) +(rule "impRight" (formula "1")) +(rule "notLeft" (formula "1")) +(rule "selectOfCreateReduce" (formula "1") (term "0") (ifseqformula "2")) + (builtin "One Step Simplification" (formula "1")) +(rule "closeTrue" (formula "1")) +) +} diff --git a/key.core/tacletProofs/heap/Taclet_selectOfStoreSameLoc.proof b/key.core/tacletProofs/heap/Taclet_selectOfStoreSameLoc.proof new file mode 100644 index 00000000000..040d26e99c7 --- /dev/null +++ b/key.core/tacletProofs/heap/Taclet_selectOfStoreSameLoc.proof @@ -0,0 +1,96 @@ +\profile "Java Profile"; + +\settings { + "Choice" : { + "JavaCard" : "JavaCard:on", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:ban", + "sequences" : "sequences:on" + }, + "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", + "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_ON", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", + "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_FULL", + "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" + } + } +} + + + +\proofObligation +// +{ + "class" : "de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput", + "name" : "selectOfStoreSameLoc" +} + +\proof { +(keyLog "0" (keyUser "bubel" ) (keyVersion "40f2ff40876dc6765d47e8d8cd9ca970f14235f7")) + +(autoModeTime "23") + +(branch "dummy ID" +(rule "eqSymm" (formula "1")) +(rule "ifthenelse_negated" (formula "1") (term "0")) +(rule "pullOutSelect" (formula "1") (term "1") (inst "selectSK=f_f_0:beta")) +(rule "simplifySelectOfStore" (formula "1")) + (builtin "One Step Simplification" (formula "1")) +(rule "ifthenelse_negated" (formula "1") (term "0")) +(rule "close" (formula "2") (ifseqformula "1")) +) +} diff --git a/key.core/tacletProofs/heap/Taclet_simplifySelectOfMemsetWithArrayRangeDiffArray.proof b/key.core/tacletProofs/heap/Taclet_simplifySelectOfMemsetWithArrayRangeDiffArray.proof new file mode 100644 index 00000000000..aeaec0bbf31 --- /dev/null +++ b/key.core/tacletProofs/heap/Taclet_simplifySelectOfMemsetWithArrayRangeDiffArray.proof @@ -0,0 +1,100 @@ +\profile "Java Profile"; + +\settings { + "Choice" : { + "JavaCard" : "JavaCard:on", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:ban", + "sequences" : "sequences:on" + }, + "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", + "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_ON", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", + "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_FULL", + "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" + } + } +} + + + +\proofObligation +// +{ + "class" : "de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput", + "name" : "simplifySelectOfMemsetWithArrayRangeDiffArray" +} + +\proof { +(keyLog "0" (keyUser "bubel" ) (keyVersion "40f2ff40876dc6765d47e8d8cd9ca970f14235f7")) + +(autoModeTime "90") + +(branch "dummy ID" +(rule "impRight" (formula "1")) +(rule "notLeft" (formula "1")) +(rule "eqSymm" (formula "2")) +(rule "pullOutSelect" (formula "1") (term "0") (inst "selectSK=f_f_0:beta")) +(rule "simplifySelectOfMemset" (formula "1")) +(rule "eqSymm" (formula "2")) +(rule "elementOfArrayRange" (formula "1") (term "0,0,0") (inst "iv=iv")) +(rule "eqSymm" (formula "1") (term "0,0,0,1,0,0,0")) +(rule "replace_known_right" (formula "1") (term "0,0,0,0") (ifseqformula "3")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "2"))) +(rule "closeFalse" (formula "1")) +) +} diff --git a/key.core/tacletProofs/heap/Taclet_simplifySelectOfStoreDiffObjects.proof b/key.core/tacletProofs/heap/Taclet_simplifySelectOfStoreDiffObjects.proof new file mode 100644 index 00000000000..96c04f8806a --- /dev/null +++ b/key.core/tacletProofs/heap/Taclet_simplifySelectOfStoreDiffObjects.proof @@ -0,0 +1,100 @@ +\profile "Java Profile"; + +\settings { + "Choice" : { + "JavaCard" : "JavaCard:on", + "Strings" : "Strings:on", + "assertions" : "assertions:on", + "bigint" : "bigint:on", + "finalFields" : "finalFields:immutable", + "initialisation" : "initialisation:disableStaticInitialisation", + "intRules" : "intRules:arithmeticSemanticsIgnoringOF", + "integerSimplificationRules" : "integerSimplificationRules:full", + "javaLoopTreatment" : "javaLoopTreatment:efficient", + "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", + "modelFields" : "modelFields:showSatisfiability", + "moreSeqRules" : "moreSeqRules:off", + "permissions" : "permissions:off", + "programRules" : "programRules:Java", + "reach" : "reach:on", + "runtimeExceptions" : "runtimeExceptions:ban", + "sequences" : "sequences:on" + }, + "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", + "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_ON", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", + "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_FULL", + "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" + } + } +} + + + +\proofObligation +// +{ + "class" : "de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput", + "name" : "simplifySelectOfStoreDiffObjects" +} + +\proof { +(keyLog "0" (keyUser "bubel" ) (keyVersion "40f2ff40876dc6765d47e8d8cd9ca970f14235f7")) + +(autoModeTime "27") + +(branch "dummy ID" +(rule "impRight" (formula "1")) +(rule "notLeft" (formula "1")) +(rule "eqSymm" (formula "2")) +(rule "pullOutSelect" (formula "1") (term "0") (inst "selectSK=f_f_0:beta")) +(rule "simplifySelectOfStore" (formula "1")) + (builtin "One Step Simplification" (formula "1")) +(rule "eqSymm" (formula "2")) +(rule "eqSymm" (formula "1") (term "0,0,0")) +(rule "replace_known_right" (formula "1") (term "0,0,0") (ifseqformula "3")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "2"))) +(rule "closeFalse" (formula "1")) +) +} From 755d3a6ae559a81ff028f7377a505973fbe006a5 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 18 Jul 2026 21:32:52 +0200 Subject: [PATCH 03/15] Park assumes-bases on a content-precise wake index The rule-application queue returns mostly bases: candidates whose \assumes formula is not yet present in the sequent. On large proofs about 97% of all queue pops are such bases, and re-matching them almost never yields an applicable rule, so the queue spends most of its time confirming that nothing changed. A base is now parked: set aside under wake keys that describe the formula it waits for, and woken exactly in the round in which a matching formula is added or changed. The keys are derived from the taclet's own compiled matcher (PatternKeySource, computed from the same per-operator dispatch the matching runs on), so what a key accepts cannot drift from what the matcher accepts. Four key kinds refine precision, from the top operator family down to the renaming-invariant hash of a concrete first argument; modality-headed formulas stay on the coarse operator key so no hash ever walks a program. The parked state lives in ParkedBases, one instance per goal, with insertion-ordered containers throughout: operator hash codes differ between runs, and a hash-ordered iteration would leak that difference into the wake order and the proof. Dead bases are swept periodically to bound the memory they hold. Waking too eagerly is harmless, the base fails to match and is parked again; the class comment argues why a wake is never late. The proofs found are statistics-identical to the unparked queue across the RunAllProofs suite. Wake keys speak one vocabulary, operator families (JavaMatchPlanBuilder.matchFamilyOf): an operator stands for itself, a parametric function instance for its base, a modality for its kind, and only schematic operators name nothing. The family is position-relative in one respect: the top of a candidate is observed after its leading updates are removed (they are the find's update context), every other position as written. An \assumes whose first argument is an update application, as in \assumes(p({u}x) ==>), therefore parks under the update application family and is woken exactly by the formulas whose first argument carries one; without the update family such a base was stored under a key no formula produces and was never woken. No shipped taclet has this shape, so the RunAllProofs suite is rule-application-identical; the shape is reachable through user-loaded taclets and is pinned by the self-wake test. The parked counts are checked against the map in the dead-base sweep, which walks the map anyway, and the wake order carries an assertion that it lists every kind: a kind missing there would silently never wake its bases. The wake cycle, the wake order, the release on waking and the sibling locality of the per-head counts are pinned by unit tests over real taclet applications. with AI tooling support --- .../main/java/de/uka/ilkd/key/proof/Goal.java | 3 +- .../rule/match/vm/ElementaryUpdateHead.java | 13 +- .../rule/match/vm/JavaMatchPlanBuilder.java | 55 ++ .../rule/match/vm/ParametricFunctionHead.java | 12 +- .../key/rule/match/vm/VMTacletMatcher.java | 43 ++ .../JavaDLMatchVMInstructionSet.java | 11 + .../MatchSchemaVariableInstruction.java | 5 + .../de/uka/ilkd/key/strategy/ParkedBases.java | 613 ++++++++++++++++++ .../strategy/QueueRuleApplicationManager.java | 362 +++-------- .../ilkd/key/strategy/RuleAppContainer.java | 2 +- .../key/strategy/ParkedBasesRuntimeTest.java | 153 +++++ ...ApplicationManagerParkingLocalityTest.java | 114 ++-- ...eueRuleApplicationManagerSelfWakeTest.java | 255 ++++++++ ...ueueRuleApplicationManagerWakeKeyTest.java | 178 +++++ .../key/strategy/StubRuleAppContainer.java | 28 + .../matcher/compiler/GenericOperatorHead.java | 7 + .../rules/matcher/compiler/MatchHead.java | 20 + .../matcher/compiler/MatchPlanBuilder.java | 35 + .../rules/matcher/compiler/ModalityHead.java | 12 +- .../matcher/compiler/PatternKeySource.java | 95 +++ 20 files changed, 1672 insertions(+), 344 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/ParkedBases.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/ParkedBasesRuntimeTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerSelfWakeTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerWakeKeyTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/StubRuleAppContainer.java create mode 100644 key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/PatternKeySource.java 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 90cb6bd7a80..95a716671d8 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 @@ -257,7 +257,8 @@ private void fireSequentChanged(SequentChangeInfo sci) { PERF_UPDATE_TAG_MANAGER.getAndAdd(time1 - time); ruleAppIndex.sequentChanged(sci); // Feed the change to the (possibly delegation-wrapped) queue manager so it can wake parked - // assumes-bases on their matching round (see QueueRuleApplicationManager#parkedByOp). + // assumes-bases on their matching round (see the parked field of + // QueueRuleApplicationManager). RuleApplicationManager m = ruleAppManager; while (m instanceof DelegationBasedRuleApplicationManager d) { m = d.getDelegate(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java index 2976c9860bd..333d2606d48 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java @@ -31,7 +31,10 @@ */ public final class ElementaryUpdateHead implements MatchHead { - /** the pattern's update operator; kept for {@link #toString} only. */ + /** + * the pattern's update operator; the operator family in {@link #topOperatorDescriptor} and + * the name in {@link #toString}. + */ private final ElementaryUpdate op; private final MatchInstruction lhsMatcher; /** whether the left-hand side is a schema variable (it advances by sibling, not by descent). */ @@ -75,6 +78,14 @@ public MatchProgram compileHeadCheck() { : null; } + @Override + public @Nullable Object topOperatorDescriptor() { + // with a concrete left-hand side exactly one update operator is accepted (elementary + // updates are interned per left-hand side); with a schema-variable left-hand side many + // are, and no single family describes them + return lhsIsSchemaVariable ? null : op; + } + @Override public String toString() { return "elemUpdate(" + op.name() + ")"; diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/JavaMatchPlanBuilder.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/JavaMatchPlanBuilder.java index ad6f5f928c4..612cb0dd3ea 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/JavaMatchPlanBuilder.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/JavaMatchPlanBuilder.java @@ -21,6 +21,7 @@ import org.key_project.prover.rules.matcher.compiler.MatchPlan; import org.key_project.prover.rules.matcher.compiler.MatchPlanBuilder; import org.key_project.prover.rules.matcher.compiler.ModalityHead; +import org.key_project.prover.rules.matcher.compiler.PatternKeySource; import org.key_project.prover.rules.matcher.vm.MatchProgram; import org.key_project.prover.rules.matcher.vm.instruction.MatchInstruction; import org.key_project.prover.rules.matcher.vm.instruction.VMInstruction; @@ -115,6 +116,60 @@ protected MatchInstruction instructionForSV(SchemaVariable sv) { return getMatchInstructionForSV(sv); } + /** + * Summarizes the {@code \assumes} pattern {@code pattern} for indexing (see + * {@link PatternKeySource}), through the same + * dispatch ({@link #headFor}) the matcher is built from. + * + * @param pattern the assumes pattern + * @return the key source of {@code pattern} + */ + public static PatternKeySource keySource( + JTerm pattern) { + return DELEGATING.keySourceFor(pattern); + } + + /** + * The operator family of a concrete operator, as a key for indexing: the counterpart of + * {@link org.key_project.prover.rules.matcher.compiler.MatchHead#topOperatorDescriptor()} + * for the operators of concrete terms (which have no match head). A key built at some + * position of a term names what the matcher observes at that position, so the family of an + * operator is the operator itself, up to the identifications the heads make (pinned by + * {@code QueueRuleApplicationManagerWakeKeyTest}): + *
    + *
  • a parametric function instance belongs to its base's family (the head accepts every + * instance of the base),
  • + *
  • a modality belongs to its kind's family (the head accepts every modality of the + * kind),
  • + *
  • every other operator, update applications and elementary updates included, is its own + * family (the generic head accepts by identity).
  • + *
+ * Only schematic operators have no family ({@code null}): a schema variable and a + * schematic modality kind fix no operator a key could name. + * + *

+ * The family is position-relative in one respect. The top of an {@code \assumes} candidate + * is matched after its leading updates have been removed (they are the find's update + * context, see {@code VMTacletMatcher.matchUpdateContext}), so a caller keying a top + * position strips leading updates before asking for the family. Every other position is + * matched as written, so updates keep their own family there. + * + * @param op the operator of a concrete term + * @return the operator's family, or {@code null} if the operator is schematic + */ + public static @Nullable Object matchFamilyOf(Operator op) { + if (op instanceof SchemaVariable) { + return null; + } + if (op instanceof ParametricFunctionInstance pfi) { + return pfi.getBase(); + } + if (op instanceof Modality mod) { + return mod.kind() instanceof ModalOperatorSV ? null : mod.kind(); + } + return op; + } + /** * The operator-specific head for {@code pattern}'s operator, or {@code null} if the operator * is not supported (or, for a modality, its program cannot be matched by the framework). diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ParametricFunctionHead.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ParametricFunctionHead.java index 4a060b8205b..b79dbf80847 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ParametricFunctionHead.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ParametricFunctionHead.java @@ -34,7 +34,10 @@ */ public final class ParametricFunctionHead implements MatchHead { - /** the pattern's parametric function; kept for {@link #toString} only. */ + /** + * the pattern's parametric function; used by {@link #topOperatorDescriptor} and + * {@link #toString}. + */ private final ParametricFunctionInstance pfi; private final MatchInstruction similar; private final MatchInstruction[] argMatchers; @@ -97,6 +100,13 @@ public MatchProgram compileHeadCheck() { }; } + @Override + public Object topOperatorDescriptor() { + // every instance with the same base function is accepted (the generic arguments are + // matched separately), so the base is the family + return pfi.getBase(); + } + @Override public String toString() { return "parametric(" + pfi.name() + ")"; diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java index 5e4978ec6d8..a0a1afb91ed 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/VMTacletMatcher.java @@ -29,6 +29,7 @@ import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; import org.key_project.prover.rules.instantiation.AssumesMatchResult; import org.key_project.prover.rules.instantiation.MatchResultInfo; +import org.key_project.prover.rules.matcher.compiler.PatternKeySource; import org.key_project.prover.rules.matcher.vm.MatchProgram; import org.key_project.prover.rules.matcher.vm.VMProgramInterpreter; import org.key_project.prover.sequent.Sequent; @@ -76,6 +77,12 @@ public class VMTacletMatcher implements TacletMatcher { /** the matcher for the taclet's assumes formulas */ private final HashMap assumesMatchPrograms = new HashMap<>(); + /** + * per assumes formula, the summary of how it accepts terms, for indexing (see + * {@link #assumesKeySource}); computed once here so it comes from the same dispatch as the + * match programs above + */ + private final HashMap assumesKeySources = new HashMap<>(); /** * the variable conditions of the taclet that need to be satisfied by found schema variable @@ -133,7 +140,43 @@ public VMTacletMatcher(Taclet taclet) { for (final SequentFormula sf : assumesSequent) { assumesMatchPrograms.put(sf.formula(), matchProgramFor((JTerm) sf.formula(), useInterpreter)); + assumesKeySources.put(sf.formula(), keySourceFor((JTerm) sf.formula())); + } + } + + /** + * The key source of an assumes pattern. Almost always the summary the plan framework + * derives; the one Java-DL correction made here: a pattern whose top is an update + * application gets no key. The top of a candidate is observed with its leading updates + * removed (the find's update context, see {@link #matchUpdateContext}), so a top key + * naming an update application could never meet a candidate's key. Deriving the summary + * of the pattern's stripped core instead would let such a pattern park; it is not keyed + * at all, so the base simply stays in the queue. + */ + private static PatternKeySource keySourceFor(JTerm pattern) { + if (pattern.op() instanceof UpdateApplication) { + return PatternKeySource.Unkeyable.INSTANCE; + } + return JavaMatchPlanBuilder.keySource(pattern); + } + + /** + * Summarizes how the given {@code \assumes} formula of this taclet accepts terms, for + * indexing candidates that wait for such a formula (see {@link PatternKeySource}). The + * summary is derived from the same dispatch as the formula's matcher, so it cannot drift + * from what {@link #matchAssumes} accepts. + * + * @param assumesFormula a formula of the taclet's {@code \assumes} sequent + * @return the formula's key source + * @throws IllegalArgumentException if the formula is not an assumes formula of this taclet + */ + public PatternKeySource assumesKeySource(Term assumesFormula) { + final PatternKeySource source = assumesKeySources.get(assumesFormula); + if (source == null) { + throw new IllegalArgumentException( + "not an assumes formula of this taclet: " + assumesFormula); } + return source; } /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/JavaDLMatchVMInstructionSet.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/JavaDLMatchVMInstructionSet.java index 7173c655b3c..bf4db7ab5a9 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/JavaDLMatchVMInstructionSet.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/JavaDLMatchVMInstructionSet.java @@ -25,6 +25,17 @@ * programs, bound-variable binding, cursor moves, and the generic identity / node-kind checks from * the framework). Both back-ends obtain their instructions here: the interpreter emits them into * its instruction stream, the compiled matcher applies element-based ones directly. + *

+ * Note for authors of new instructions: the proof-search queue indexes waiting rule applications + * by the operator families their {@code \assumes} formulas could match. The families are stated + * by the match heads themselves + * ({@link org.key_project.prover.rules.matcher.compiler.MatchHead#topOperatorDescriptor()}, an + * abstract method, so a new head cannot omit the decision) and, for the operators of concrete + * terms, by {@link de.uka.ilkd.key.rule.match.vm.JavaMatchPlanBuilder#matchFamilyOf}. An + * instruction that accepts more than one operator in a position, like + * {@link #getSimilarParametricFunctionInstruction}, belongs to a head whose descriptor names the + * family, and {@code matchFamilyOf} must agree with it (pinned by + * {@code QueueRuleApplicationManagerWakeKeyTest}). */ public final class JavaDLMatchVMInstructionSet { diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/MatchSchemaVariableInstruction.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/MatchSchemaVariableInstruction.java index 09de0cb7c1c..aa0c7b29f38 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/MatchSchemaVariableInstruction.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/instructions/MatchSchemaVariableInstruction.java @@ -61,6 +61,11 @@ protected final MatchConditions addInstantiation(JTerm term, MatchResultInfo mat final JTerm t = inst.getTermInstantiation(op, inst.getExecutionContext(), services); if (t != null) { + // An already instantiated schema variable accepts a candidate exactly when it is + // equal to the instantiation modulo renaming. The proof-search queue relies on this: + // it indexes waiting rule applications by hashCodeModRenaming of the instantiation + // (QueueRuleApplicationManager), and that hash is only a safe filter as long as the + // comparison here is not more liberal than equality modulo renaming. if (!RENAMING_TERM_PROPERTY.equalsModThisProperty(t, term)) { return null; } else { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/ParkedBases.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/ParkedBases.java new file mode 100644 index 00000000000..52559a642f7 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/ParkedBases.java @@ -0,0 +1,613 @@ +/* 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.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; + +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.op.JModality; +import de.uka.ilkd.key.logic.op.UpdateApplication; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.rule.NoPosTacletApp; +import de.uka.ilkd.key.rule.match.vm.JavaMatchPlanBuilder; +import de.uka.ilkd.key.rule.match.vm.VMTacletMatcher; + +import org.key_project.logic.Term; +import org.key_project.logic.op.Modality; +import org.key_project.prover.rules.matcher.compiler.PatternKeySource; +import org.key_project.prover.sequent.Sequent; +import org.key_project.prover.sequent.SequentFormula; + +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Candidates of a {@link QueueRuleApplicationManager} that are currently set aside, grouped by + * the formula they are waiting for. + * + *

+ * Some vocabulary. A rule of KeY is called a taclet. A taclet may carry an + * {@code \assumes} part: one or more formulas that must already be present in the sequent for + * the rule to be applicable. A candidate whose {@code \assumes} formula is not present yet is + * called a base here: it cannot be applied now, but it may become applicable in a + * later round once such a formula appears. Deciding a taclet's applicability means + * matching its formulas against the sequent, where a schema variable in the taclet + * (a placeholder) stands for an arbitrary concrete term. Matching a taclet against the whole + * sequent every round is the expensive operation this class avoids. + * + *

+ * Measurements on a large proof: almost every candidate returned by the queue is a base whose + * {@code \assumes} still does not match (about 96.8%), and re-matching it almost never + * produces a new applicable rule (about 97 to 99.6% of the time it produces nothing). So + * instead of returning such a base every round only to match and discard it, it is held back. + * Setting a base aside is called parking it ({@link #park}); putting it back into the + * queue is called waking it. A parked base is stored under one or more {@link WakeKey}s + * that describe the formula it is waiting for ({@link #parkKeys}), and is woken as soon as a + * formula matching such a key is added to or changed in the sequent + * ({@link #recordWakeKeysOf}, {@link #drainWoken}). + * + *

+ * This is intended to find the same proof as returning every base every round. A base that + * is woken too eagerly does no harm: it is returned, fails to match, and is parked again, + * exactly as an un-parked base would have behaved that round. A base that is woken too late + * would change the proof, because the rule application it produces would be created, and so + * aged (see the comment on {@link QueueRuleApplicationManager}), in a later round. The + * following points show that a wake is never late. + *

    + *
  • A base is parked only if the top operator (the outermost function or connective) of each + * of its {@code \assumes} formulas is either concrete or a schema variable that the rule's + * main match already fixed to a concrete term (see {@link #parkKeys}). If some top operator is + * an unfixed schema variable, the formula would match anything, so the base is not parked and + * stays in the queue as before. What a pattern could accept is stated by the taclet's own + * matcher ({@link VMTacletMatcher#assumesKeySource}), derived from the same dispatch its + * matching is built from, so park keys and matching cannot drift apart.
  • + *
  • A parked base is woken in exactly the round in which a formula it could match is added + * or changed. That is the same round in which an un-parked copy would first see that formula + * as new and become applicable. So the resulting rule application is created in the same round + * either way, with the same age and cost.
  • + *
  • A formula may be wrapped in a chain of updates (an update is a pending + * assignment written in front of a formula, as in {@code {x := 1} phi}). The matcher removes + * this update chain before it matches. The keys of kind {@link WakeKind#OP} therefore use the + * top operator of the formula and of every formula obtained by removing one update from the + * front, which is a safe over-approximation of what the matcher could accept.
  • + *
  • The other three key kinds filter more precisely, using only conditions the matcher + * checks literally. A base whose {@code \assumes} first argument is a concrete term can only + * match a formula whose first argument has the same top operator ({@link WakeKind#ARG_OP}). A + * base whose {@code \assumes} first argument (or whole formula) was fixed to a concrete term + * by the main match can only match a formula equal to it up to renaming of bound variables, + * and equal terms up to that renaming have the same {@link JTerm#hashCodeModRenaming()}, so + * filtering by that hash ({@link WakeKind#ARG_HASH}, {@link WakeKind#WHOLE_HASH}) never drops + * a formula the matcher would accept. Parking and waking hash the formula after its update + * chain has been removed, so the two sides compare the same thing.
  • + *
  • No hash is ever computed over a term whose top operator is a modality (a program + * nested deeper is still hashed; the guard is by the top operator). Such a term + * carries a program, and its hash walks that whole program; in a proof that executes a large + * program step by step, the changed formula is a fresh term every step, so nothing is cached + * and the walks add up to time quadratic in the program size. A base waiting for such a + * formula is parked under the coarse {@link WakeKind#OP} key of the modality kind instead + * ({@link #parkKeys}), and the wake side then stops at that key for modality formulas + * ({@link #recordWakeKeysOf}). The base is woken whenever any formula of that kind changes, + * which is more often than the exact hash would wake it, and that is harmless (see + * above).
  • + *
+ *

+ * One assumption remains. A parked container keeps the cost it was parked with, while an + * un-parked base is re-costed with a fresh age share every time the queue returns it. The + * two runs still perform the same proof steps as long as, in every round and in both runs, + * all candidates cheaper than the rule application the round finally selects are processed + * in that round. Every measurement so far satisfies this (statistics-identical benchmark + * runs and the RunAllProofs suite), but it is an assumption about the costs the strategy + * produces, not a proven theorem. A statistics comparison against a run without parking and + * a RunAllProofs run are therefore mandatory when changing anything in this area. + *

+ * Three implementation notes. The map, its buckets, and {@link #pendingWakeKeys} must stay + * insertion-ordered: the hash codes of operators differ from run to run, so iterating a + * plain hash-ordered container would make the wake order, and with it the proof, differ from + * run to run. A parked base whose find position has meanwhile disappeared from the + * sequent is not removed at that moment; it is removed by {@link #sweepDeadParkedBases}, + * which keeps the memory held by such bases bounded (see there). Waking such a base is also + * harmless: its re-expansion notices that it is no longer applicable and drops it. And a + * changed formula only produces keys under whose head and kind some base is currently + * parked (see {@link #recordWakeKeysOf} for why no wake can be missed); without this filter, + * every change of a possibly very large formula would compute the two hashes, which walk + * the whole formula, even in a proof that parks nothing or parks nothing with that head. + */ +@NullMarked +final class ParkedBases { + /** + * The parked bases, grouped by the key of the formula they wait for. A bucket is a plain + * {@link ArrayList} while small: a base is parked at most once per bucket and bases compare + * by object identity, so there is nothing to de-duplicate and a set would waste memory. A + * bucket past {@link #BUCKET_SET_THRESHOLD} becomes a {@link LinkedHashSet} to keep removing + * a woken base by value constant time (see {@link #park}). + */ + private @Nullable LinkedHashMap> parked = null; + + /** + * Bucket size at which a parking bucket is promoted from ArrayList to LinkedHashSet. + */ + private static final int BUCKET_SET_THRESHOLD = 16; + + /** + * The {@link WakeKey}s of every formula that was added to or changed in the sequent since the + * previous round. {@link #drainWoken()} reads and then empties this set at the start of + * the next round to decide which parked bases to wake. {@code null} until the first change is + * recorded. Package-private for the unit tests in this package. + */ + @Nullable + LinkedHashSet pendingWakeKeys = null; + + /** + * Number of {@link #park} calls since the last {@link #sweepDeadParkedBases}, and the + * number of parked containers that survived that sweep. Together they trigger the next + * sweep: both counters depend only on this goal's own history, so the sweep runs at the + * same point in every run. + */ + private int parksSinceSweep = 0; + private int survivorsAtLastSweep = 0; + + /** + * Number of entries of the parked map per key head and {@link WakeKind}: the array under a + * head holds one count per kind, indexed by its ordinal. {@link #recordWakeKeysOf} skips + * every key whose head and kind have no parked base, and in particular computes no hash + * then; see there for why this cannot suppress a needed wake. The map is only queried by + * key, never iterated in a way the proof could observe, so a plain {@link HashMap} is safe + * here. Kept up to date by {@link #park}, {@link #unindexParked}, and + * {@link #sweepDeadParkedBases}. + */ + private final HashMap parkedCountsByHead = new HashMap<>(); + + /** Number of {@link WakeKind}s, the length of the count arrays above. */ + private static final int KINDS = WakeKind.values().length; + + /** Minimum number of parks before the first sweep, so small proofs never sweep. */ + private static final int SWEEP_FLOOR = 64; + + /** + * How precisely a {@link WakeKey} describes the formula a parked base waits for. Below, + * core means the formula after its update chain has been removed (see the class + * comment), and descriptor refers to an operator family as defined by the matcher + * ({@link JavaMatchPlanBuilder#matchFamilyOf} for concrete operators, + * {@link org.key_project.prover.rules.matcher.compiler.PatternKeySource} for patterns). + */ + enum WakeKind { + /** The extra value is absent; the key uses only a descriptor of a top operator. */ + OP, + /** The extra value is the descriptor of the core's first argument's top operator. */ + ARG_OP, + /** The extra value is {@link JTerm#hashCodeModRenaming()} of the core's first argument. */ + ARG_HASH, + /** The extra value is {@link JTerm#hashCodeModRenaming()} of the whole core. */ + WHOLE_HASH + } + + /** + * One entry key of the parked map. It holds the precision {@code kind}, the side of the + * sequent the formula is expected on ({@code inAntecedent}; an {@code \assumes} formula is + * only ever matched against formulas of its own side, so keys of different sides never + * meet), the descriptor {@code head} of the (core) formula's top operator (its operator + * family, see above), and one + * extra value whose meaning depends on the kind (see {@link WakeKind}): {@code null} for + * {@link WakeKind#OP}, a descriptor for {@link WakeKind#ARG_OP}, an {@link Integer} hash for + * the two hash kinds. A parked base is stored under the most precise key its {@code \assumes} + * shape allows ({@link #parkKeys}). A changed formula produces every key a base could match + * it with ({@link #recordWakeKeysOf}). A base is therefore woken exactly when some changed + * formula produces a key equal to one the base is stored under. + */ + record WakeKey(WakeKind kind, boolean inAntecedent, Object head, @Nullable Object datum) { + } + + /** + * The order in which {@link #drainWoken()} collects woken bases across the four kinds. + * Bases are put back into the queue in the order they are collected, and that order decides + * how the queue arranges candidates of equal cost, so it must stay fixed for the proof to stay + * the same. + */ + private static final WakeKind[] WAKE_ORDER = + { WakeKind.OP, WakeKind.ARG_HASH, WakeKind.ARG_OP, WakeKind.WHOLE_HASH }; + static { + // A kind missing here would never wake its bases; the proof-relevant property of the + // order itself is only that it is fixed. + assert new HashSet<>(Arrays.asList(WAKE_ORDER)).size() == WakeKind.values().length + : "WAKE_ORDER must list every WakeKind exactly once"; + } + + /** + * The keys under which the given base is stored in the parked map: a single precise key when + * the shape of the base's {@code \assumes} allows one, otherwise one {@link WakeKind#OP} key + * per {@code \assumes} formula. Returns {@code null} when the base cannot be parked at all, + * that is when some {@code \assumes} top operator is a schema variable the main match did not + * fix to a concrete term; such a base stays in the queue. A base whose formula or hashed + * term has a modality at the top gets no precise key and falls through to the coarse + * {@link WakeKind#OP} case; see the class comment for why modality terms are never hashed. + *

+ * What each {@code \assumes} pattern could accept is not analyzed here: the taclet's matcher + * summarizes each of its assumes formulas ({@link VMTacletMatcher#assumesKeySource}), derived + * from the same per-operator dispatch its matching is built from, so the keys cannot drift + * from what the matcher accepts. This method only combines those summaries with the main + * match's instantiations, and picks the most precise {@link WakeKind} they allow. + */ + static @Nullable List parkKeys(NoPosTacletApp app) { + if (!(app.taclet().getMatcher() instanceof VMTacletMatcher matcher)) { + return null; + } + final Sequent assumesSeq = app.taclet().assumesSequent(); + if (assumesSeq.size() == 1) { + final boolean inAntec = !assumesSeq.antecedent().isEmpty(); + final Term pattern = + assumesSeq.iterator().next().formula(); + final PatternKeySource source = matcher.assumesKeySource(pattern); + if (source instanceof PatternKeySource.ByWholeSchemaVariable whole) { + if (app.instantiations().getInstantiation(whole.sv()) instanceof JTerm instTerm) { + // the main match fixed the whole assumes formula (rules replace_known_* and + // close); key on the hash of its core, the same form the wake side hashes + JTerm core = instTerm; + while (core.op() instanceof UpdateApplication) { + core = UpdateApplication.getTarget(core); + } + final Object head = JavaMatchPlanBuilder.matchFamilyOf(core.op()); + if (head != null && !(core.op() instanceof JModality)) { + return List.of(new WakeKey(WakeKind.WHOLE_HASH, inAntec, head, + core.hashCodeModRenaming())); + } + } + } else if (source instanceof PatternKeySource.ByHead byHead + && !(byHead.headDescriptor() instanceof Modality.Kind)) { + if (byHead + .firstArg() instanceof PatternKeySource.FirstArg.ByArgSchemaVariable argSv) { + if (app.instantiations() + .getInstantiation(argSv.sv()) instanceof JTerm instTerm + && !(instTerm.op() instanceof JModality)) { + // the main match fixed the assumes first argument (the applyEq family: + // \assumes(s = t1) with s already bound to the term being rewritten) + return List.of(new WakeKey(WakeKind.ARG_HASH, inAntec, + byHead.headDescriptor(), instTerm.hashCodeModRenaming())); + } + } else if (byHead + .firstArg() instanceof PatternKeySource.FirstArg.ByArgHead argHead) { + // the assumes first argument is itself a term with a fixed top operator + // (for example \assumes(store(h, o, f1, x) = EQ)) + return List.of(new WakeKey(WakeKind.ARG_OP, inAntec, + byHead.headDescriptor(), argHead.descriptor())); + } + } + } + return assumesOpKeys(app, matcher); + } + + /** + * One {@link WakeKind#OP} key per {@code \assumes} formula of the given taclet application, + * on the formula's own side of the sequent: the key's family comes from the formula's key + * source, or, for a schema-variable top, from the operator the main match fixed it to. + * Returns {@code null} if the application has no {@code \assumes} formulas, or if some + * formula yields no family (an unfixed schema variable would match anything; an update + * application or a schematic modality kind cannot be keyed). Used for a base that none of + * the precise cases in {@link #parkKeys} apply to. + */ + private static @Nullable List assumesOpKeys(NoPosTacletApp app, + VMTacletMatcher matcher) { + final Sequent assumesSeq = app.taclet().assumesSequent(); + if (assumesSeq.isEmpty()) { + return null; + } + // one key per distinct family and side: several assumes formulas may share a top + // operator, and a base must be stored at most once per bucket + final LinkedHashSet keys = new LinkedHashSet<>(assumesSeq.size()); + for (int side = 0; side < 2; side++) { + final boolean inAntec = side == 0; + for (SequentFormula sf : inAntec ? assumesSeq.antecedent() : assumesSeq.succedent()) { + final PatternKeySource source = matcher.assumesKeySource(sf.formula()); + final Object head; + if (source instanceof PatternKeySource.ByHead byHead) { + head = byHead.headDescriptor(); + } else if (source instanceof PatternKeySource.ByWholeSchemaVariable whole + && app.instantiations() + .getInstantiation(whole.sv()) instanceof JTerm instTerm) { + // This keys a top position, which the wake side observes with leading + // updates stripped, so an update-headed instantiation has no key a wake + // could meet. Such a base is left unparked rather than stripped here, + // because parking it changes which candidates carry their parked cost. + head = instTerm.op() instanceof UpdateApplication ? null + : JavaMatchPlanBuilder.matchFamilyOf(instTerm.op()); + } else { + head = null; + } + if (head == null) { + return null; + } + keys.add(new WakeKey(WakeKind.OP, inAntec, head, null)); + } + } + return List.copyOf(keys); + } + + /** + * Set the given base aside, under each of its {@link #parkKeys}. + * + * @param base the re-costed base container to park (carries the current age) + * @param goal the goal the base belongs to, used by the dead-base sweep + * @return {@code true} if the base was parked, {@code false} if it cannot be parked (see + * {@link #parkKeys}) and the caller must keep it in the queue + */ + boolean park(TacletAppContainer base, @Nullable Goal goal) { + final List keys = parkKeys(base.getTacletApp()); + if (keys == null) { + return false; + } + if (parked == null) { + parked = new LinkedHashMap<>(); + } + for (WakeKey key : keys) { + final Collection bucket = + parked.computeIfAbsent(key, k -> new ArrayList<>(4)); + bucket.add(base); + parkedCountsByHead.computeIfAbsent(key.head(), h -> new int[KINDS])[key.kind() + .ordinal()]++; + if (bucket.size() == BUCKET_SET_THRESHOLD && bucket instanceof ArrayList) { + parked.put(key, new LinkedHashSet<>(bucket)); + } + } + parksSinceSweep++; + if (parksSinceSweep >= survivorsAtLastSweep + SWEEP_FLOOR) { + sweepDeadParkedBases(goal); + } + return true; + } + + /** + * Remove every parked base that can no longer be applied because its find position has + * disappeared from the sequent (the same test, {@link TacletAppContainer#isStillApplicable}, + * that would drop the base if it were woken). Such bases would otherwise stay parked until + * their key happens to fire, holding on to their rule application and the old formulas it + * points to. The sweep runs from {@link #park} once the number of parks since the last sweep + * reaches the number of survivors of that sweep (plus a floor for small proofs), so it walks + * the whole map at most once per doubling: the cost per park is constant on average, and the + * map never holds more than about twice the still-applicable bases. Removal keeps the + * insertion order of the surviving entries, and the trigger depends only on this goal's own + * park history, so the sweep does not introduce run-to-run differences. + */ + private void sweepDeadParkedBases(@Nullable Goal goal) { + if (parked == null || goal == null) { + return; + } + assert parkedCountsConsistent() : "parkedCountsByHead out of step with the parked map"; + parksSinceSweep = 0; + survivorsAtLastSweep = 0; + final Goal g = goal; + // the sweep walks every entry anyway, so the counts are recomputed from scratch + // instead of tracking each removal + parkedCountsByHead.clear(); + final var entries = parked.entrySet().iterator(); + while (entries.hasNext()) { + final var entry = entries.next(); + final Collection bucket = entry.getValue(); + bucket.removeIf(c -> c instanceof TacletAppContainer tac && !tac.isStillApplicable(g)); + if (bucket.isEmpty()) { + entries.remove(); + } else { + survivorsAtLastSweep += bucket.size(); + final WakeKey key = entry.getKey(); + parkedCountsByHead.computeIfAbsent(key.head(), h -> new int[KINDS])[key.kind() + .ordinal()] += bucket.size(); + } + } + } + + /** + * The parked bases that some formula changed since the previous round could match (see + * {@link #pendingWakeKeys}); the caller puts them back into the queue. Bases are collected + * one {@link WakeKind} at a time in {@link #WAKE_ORDER}, within a kind in the order the + * changes were recorded, and each collected base is removed from the parked map. Empties + * the pending change set. + * + * @return the woken bases in wake order; empty if nothing is to be woken + */ + Collection drainWoken() { + if (pendingWakeKeys == null) { + return List.of(); + } + LinkedHashSet woken = null; + if (parked != null && !parked.isEmpty()) { + for (WakeKind kind : WAKE_ORDER) { + for (WakeKey key : pendingWakeKeys) { + if (key.kind() != kind) { + continue; + } + final Collection bucket = parked.get(key); + if (bucket != null) { + if (woken == null) { + woken = new LinkedHashSet<>(); + } + woken.addAll(bucket); + } + } + } + } + pendingWakeKeys.clear(); + if (woken == null) { + return List.of(); + } + for (RuleAppContainer c : woken) { + unindexParked(c); + } + return woken; + } + + /** + * Remove a base that is being woken from every bucket that holds it. The keys are recomputed + * by {@link #parkKeys}; this yields the keys the base was stored under, because everything + * they are computed from (the taclet, its instantiations, the cached hashes) is never + * modified after the base was parked. A failed removal would mean this assumption broke and + * the base would stay in the map forever, hence the asserts. + */ + private void unindexParked(RuleAppContainer c) { + if (parked == null || !(c instanceof TacletAppContainer tac)) { + return; + } + final List keys = parkKeys(tac.getTacletApp()); + if (keys == null) { + return; + } + for (WakeKey key : keys) { + final Collection bucket = parked.get(key); + assert bucket != null : "woken base has no bucket under its park key"; + if (bucket != null) { + final boolean removed = bucket.remove(c); + assert removed : "woken base was not stored in its park bucket"; + if (removed) { + final int[] counts = parkedCountsByHead.get(key.head()); + if (counts != null && --counts[key.kind().ordinal()] == 0 + && Arrays.stream(counts).allMatch(n -> n == 0)) { + parkedCountsByHead.remove(key.head()); + } + } + if (bucket.isEmpty()) { + parked.remove(key); + } + } + } + } + + /** + * Add to {@link #pendingWakeKeys} every {@link WakeKey} that the given formula could let a + * parked base match. This is the wake counterpart of {@link #parkKeys}: the two produce the + * same kinds of keys, so a base is woken exactly when a changed formula could match it. + *

+ * Keys are only computed when a base is currently parked under the same head and kind + * ({@link #parkedCountsByHead}). This cannot suppress a needed wake. A key without such a + * base has no base to wake now, and a base parked later does not need it either: within a + * round the prover first picks candidates from the queue, which is when bases are parked, + * and then applies the chosen rule, which is when formula changes are recorded. So every + * change is recorded after all parks of its round, with the counts already raised, and a + * change recorded before a base was parked concerns a formula the base's own failed match + * already saw in the sequent. Skipping by head is also what makes recording cheap. The head + * costs only the walk down the update chain. The two hashes, which walk the whole formula, + * are computed only when a base is actually waiting for a formula with this head; without + * this test, a proof step that changes a large formula, such as one carrying a whole + * program, would hash it even though no base waits for such a formula. + */ + void recordWakeKeysOf(Term formula, boolean inAntecedent) { + if (parked == null || parked.isEmpty()) { + return; + } + // Strip the leading updates the matcher would strip before matching, so both sides key + // on the same core; only the top position is observed stripped, an update application + // at the core's first argument keeps its own family below. + Term t = formula; + while (t.op() instanceof UpdateApplication && t instanceof JTerm jt) { + t = UpdateApplication.getTarget(jt); + } + final Object head = JavaMatchPlanBuilder.matchFamilyOf(t.op()); + if (head == null) { + return; + } + final int[] counts = parkedCountsByHead.get(head); + if (counts == null) { + return; + } + if (pendingWakeKeys == null) { + pendingWakeKeys = new LinkedHashSet<>(); + } + if (counts[WakeKind.OP.ordinal()] > 0) { + pendingWakeKeys.add(new WakeKey(WakeKind.OP, inAntecedent, head, null)); + } + if (head instanceof Modality.Kind) { + // no hash keys exist for modality formulas (see parkKeys), so nothing else to do + return; + } + if (t instanceof JTerm core) { + if (counts[WakeKind.WHOLE_HASH.ordinal()] > 0) { + pendingWakeKeys.add(new WakeKey(WakeKind.WHOLE_HASH, inAntecedent, head, + core.hashCodeModRenaming())); + } + if (core.arity() > 0 && core.sub(0) instanceof JTerm firstArg) { + if (counts[WakeKind.ARG_OP.ordinal()] > 0) { + final Object argHead = JavaMatchPlanBuilder.matchFamilyOf(firstArg.op()); + if (argHead != null) { + pendingWakeKeys.add( + new WakeKey(WakeKind.ARG_OP, inAntecedent, head, argHead)); + } + } + if (counts[WakeKind.ARG_HASH.ordinal()] > 0 + && !(firstArg.op() instanceof JModality)) { + pendingWakeKeys.add(new WakeKey(WakeKind.ARG_HASH, inAntecedent, head, + firstArg.hashCodeModRenaming())); + } + } + } + } + + /** + * A deep copy for a goal that splits into two: fresh map, fresh buckets, fresh pending set, + * so the two goals park and wake independently (see the copy method of + * {@link QueueRuleApplicationManager} for why sharing would change proofs). The stored + * containers and the key components are never modified in place and stay shared. The copy + * starts with the same parked population, so it inherits the sweep counters. + */ + ParkedBases copy() { + final ParkedBases res = new ParkedBases(); + if (parked != null) { + final LinkedHashMap> copy = + new LinkedHashMap<>(parked.size()); + for (var e : parked.entrySet()) { + final Collection v = e.getValue(); + copy.put(e.getKey(), + v instanceof LinkedHashSet ? new LinkedHashSet<>(v) : new ArrayList<>(v)); + } + res.parked = copy; + } + if (pendingWakeKeys != null) { + res.pendingWakeKeys = new LinkedHashSet<>(pendingWakeKeys); + } + res.parksSinceSweep = parksSinceSweep; + res.survivorsAtLastSweep = survivorsAtLastSweep; + for (var e : parkedCountsByHead.entrySet()) { + res.parkedCountsByHead.put(e.getKey(), e.getValue().clone()); + } + return res; + } + + /** Consistency of {@link #parkedCountsByHead} with the parked map, for asserts. */ + private boolean parkedCountsConsistent() { + final HashMap expected = new HashMap<>(); + if (parked != null) { + for (var e : parked.entrySet()) { + final WakeKey key = e.getKey(); + expected.computeIfAbsent(key.head(), h -> new int[KINDS])[key.kind().ordinal()] += + e.getValue().size(); + } + } + if (!expected.keySet().equals(parkedCountsByHead.keySet())) { + return false; + } + for (var e : expected.entrySet()) { + if (!Arrays.equals(e.getValue(), parkedCountsByHead.get(e.getKey()))) { + return false; + } + } + return true; + } + + /** Access to the parked map for the deep-copy test in this package. */ + @Nullable + LinkedHashMap> parkedMapForTests() { + return parked; + } + + /** Insert an entry under the given key, bypassing {@link #parkKeys}; only for tests. */ + void parkForTests(WakeKey key, RuleAppContainer entry) { + if (parked == null) { + parked = new LinkedHashMap<>(); + } + parked.computeIfAbsent(key, k -> new ArrayList<>(4)).add(entry); + parkedCountsByHead.computeIfAbsent(key.head(), h -> new int[KINDS])[key.kind().ordinal()]++; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManager.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManager.java index 2ae307a0523..f6db96a6200 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManager.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManager.java @@ -8,23 +8,14 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicLong; -import de.uka.ilkd.key.logic.JTerm; -import de.uka.ilkd.key.logic.op.UpdateApplication; import de.uka.ilkd.key.proof.Goal; -import de.uka.ilkd.key.rule.NoPosTacletApp; -import de.uka.ilkd.key.rule.inst.SVInstantiations; -import org.key_project.logic.op.Operator; -import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.proof.ProofGoal; import org.key_project.prover.rules.RuleApp; import org.key_project.prover.sequent.FormulaChangeInfo; import org.key_project.prover.sequent.PosInOccurrence; -import org.key_project.prover.sequent.Sequent; import org.key_project.prover.sequent.SequentChangeInfo; import org.key_project.prover.sequent.SequentFormula; import org.key_project.prover.strategy.RuleApplicationManager; @@ -49,36 +40,41 @@ * {@link RuleApp} is computed according to a given {@link Strategy} (see * {@link Feature#computeCost(RuleApp, PosInOccurrence, ProofGoal, MutableState)}). * - *

Determinism invariant — assumes-base parking is goal-local (do not break under MT)

+ *

Why the set-aside state of this class belongs to one goal only

* - * The assumes-base parking/wake state ({@link #parkedByOp} / {@link #pendingWakeOps}) is - * strictly goal-local: exactly one manager instance per {@link Goal}, deep-copied - * on split ({@link #clone()}), built only from insertion-ordered structures ({@link LinkedHashMap} - * / - * {@link ArrayList} / {@link LinkedHashSet}) with interned-operator keys. This is not merely a - * thread-safety measure -- it is load-bearing for proof reproducibility. A - * rule-application - * candidate's birth-age (the age baked into its {@link RuleAppContainer} when it enters - * the - * queue) is fixed by which round its assumes-base is woken (see {@link #parkedByOp}), and - * that age drives the cost/tie-break ordering of the entire search. A goal's wake volume and timing - * are a pure function of that goal's own deterministic rule- and sequent-change history, - * independent - * of thread scheduling; that is exactly what keeps the multi-worker prover byte-identical to the - * single-threaded one on this path (the residual MT variance was root-caused elsewhere -- shared - * caches, the veto fingerprint, naming, the tie-break -- and never to parking). + * Some vocabulary first. A {@link Goal} is one open branch of the proof, and its + * {@code Sequent} is the collection of formulas that this branch currently consists of. The + * automatic proof search runs in rounds: in each round it asks this manager for the next + * rule application, performs it, and thereby changes the sequent. The age of a goal is + * the number of rule applications performed on it so far ({@code Goal.getTime()}). * *

- * Therefore, for anyone evolving the multi-core prover: the wake path must stay - * goal-confined and {@link #sequentChanged} events must be delivered in the goal's own - * order. Any optimization that perturbs a goal's wake/birth timing -- a wake cache shared across - * goals, speculative cross-goal base reuse, or coalesced/reordered {@code sequentChanged} - * notifications -- would silently change proofs (they would diverge, not crash, - * and - * no test that only checks closure would notice). The goal-locality of the copy is pinned by - * {@code QueueRuleApplicationManagerParkingLocalityTest}; end-to-end determinism (single-threaded - * == - * parallel) is pinned by {@code ProofEquivalenceTest} / {@code MtDeterminismCiTest}. + * A {@link RuleAppContainer} stores one possible rule application together with its cost, and the + * cost includes the age the goal had when the container was created. The round in which a + * container is created therefore decides its cost, the cost decides the order in which this + * manager returns candidates, and that order decides which proof is found. + * + *

+ * Candidates that cannot be applied yet are set aside rather than kept in the queue, and are put + * back in a later round (see {@link ParkedBases}). The round in which one is put back decides when + * it + * is created anew, and so, by the paragraph above, it decides the proof. This is why + * the parking state ({@link ParkedBases}) belongs to a single goal: there is one manager per + * goal, it is copied when a goal splits into two ({@link #clone()}), and it uses only collections + * that keep insertion order ({@link LinkedHashMap}, {@link ArrayList}, {@link LinkedHashSet}). + * A goal then sets aside and puts back candidates as a function of its own rule applications + * alone, independent of how threads happen to be scheduled. That is what lets the prover find the + * same proof whether it uses one worker thread or several. + * + *

+ * For anyone changing this class: this state must not be shared between goals, + * and {@link #sequentChanged} must be called in the order in which the goal changed its sequent. + * Sharing the state across goals, reusing candidates of one goal in another, or combining or + * reordering {@code sequentChanged} calls changes ages, hence costs, hence proofs. Such a change + * does not cause a crash, and a test that only checks whether a proof closes does not notice it. + * {@code QueueRuleApplicationManagerParkingLocalityTest} checks that a copy shares no state with + * its original. {@code ProofEquivalenceTest} and {@code MtDeterminismCiTest} check that several + * worker threads find the same proof as one. */ @NullMarked public class QueueRuleApplicationManager implements RuleApplicationManager { @@ -113,57 +109,12 @@ public class QueueRuleApplicationManager implements RuleApplicationManager private long nextRuleTime; /** - * Parked assumes-incomplete taclet bases, indexed by the concrete top operator(s) of their - * {@code \assumes} formulas. Such bases re-expand to nothing (no new assumes match) on almost - * every round (profiling: 96.8% of queue pops fail at the unmatched {@code \assumes}, and - * 97-99.6% of the resulting re-expansions yield no new instance -- the dominant remaining queue - * churn), so instead of re-popping and re-expanding them each round they are parked here and - * woken only when a formula they could match appears. A base is stored under each of its wake - * operators and woken when any of them is added/modified. Insertion-ordered for determinism; - * {@code null} until the first base is parked. - *

- * Sound (byte-identical) by construction, unlike the earlier sequent-growth heuristic: - *

    - *
  • Only effectively-indexable bases are parked -- every {@code \assumes} formula's - * top operator is concrete or a schema variable already bound by the find-match (see - * {@link #assumesWakeOps}). Bases with an unbound-generic top (which would match any formula) - * are never parked; they stay in the active queue and re-expand every round exactly as without - * parking.
  • - *
  • A parked base is woken (re-inserted into the active queue) on exactly the round a formula - * with a matching top operator is added or modified ({@link #sequentChanged}/{@code - * pendingWakeOps}) -- the same round its non-parked counterpart would first see that formula as - * "new" and re-expand to the instance. So the instance enters the queue at the identical round, - * with the identical (current) age and cost, and the proof is byte-identical.
  • - *
  • The wake set is a sound superset: it walks the changed formula's update-prefix - * spine of operators (the assumes matcher strips the update context before matching, see - * {@code VMTacletMatcher.matchUpdateContext}). Over-waking is harmless -- a spuriously woken - * base - * is popped, re-expands to nothing, and is re-parked, exactly as a non-parked base would behave - * that round. Only missing a wake would diverge, and that cannot happen for an - * effectively-indexable base.
  • - *
  • All structures are insertion-ordered ({@link LinkedHashMap}/{@link ArrayList}/ - * {@link LinkedHashSet}) so parking introduces no non-determinism.
  • - *
- */ - // The per-operator buckets are plain ArrayLists, not sets, while small. A base is parked at - // most - // once per bucket (removed from all its buckets when woken; see unindexParked) and - // RuleAppContainer uses identity equality, so there is nothing to de-duplicate -- whereas a set - // would spend a whole LinkedHashMap (16-slot table + a 40-byte Entry per element) to hold a - // handful of refs. A bucket that grows past {@link #BUCKET_SET_THRESHOLD} is switched to a - // LinkedHashSet so the by-value unindexParked stays O(1) (see park). - private @Nullable LinkedHashMap> parkedByOp = null; - /** - * Bucket size at which a per-operator parking bucket is promoted from ArrayList to - * LinkedHashSet. + * Candidates that are currently set aside because their {@code \assumes} formulas have no + * match in the sequent yet, together with the machinery to file and wake them; see + * {@link ParkedBases}. One instance per manager, replaced on {@link #clearCache()}, + * deep-copied on {@link #clone()}. */ - private static final int BUCKET_SET_THRESHOLD = 16; - /** - * Top operators (along the update-prefix spine) of formulas added/modified since the previous - * round; the wake candidates consumed at the start of the next round. Insertion-ordered for - * determinism; {@code null} until the first change is recorded. - */ - private @Nullable LinkedHashSet pendingWakeOps = null; + private ParkedBases parking = new ParkedBases(); @Override public void setGoal(Goal p_goal) { @@ -177,8 +128,7 @@ public void setGoal(Goal p_goal) { public void clearCache() { queue = null; previousMinimum = null; - parkedByOp = null; - pendingWakeOps = null; + parking = new ParkedBases(); if (goal != null) { goal.proof().getServices().getCaches().getIfInstantiationCache().releaseAll(); } @@ -379,14 +329,9 @@ private void computeNextRuleApp(ImmutableHeap<@NonNull RuleAppContainer> further */ ImmutableList workingList = ImmutableList.nil(); - // Wake parked assumes-bases whose \assumes top operator matches a formula added/modified - // since the last round, re-inserting them into the active queue so they re-expand during - // THIS - // round -- the identical round their non-parked counterparts would first see that formula - // as - // new. No completeness net is needed (or wanted): an effectively-indexable base is always - // woken on its matching round, and a late re-injection would surface its instance at the - // wrong round, the very divergence parking must avoid. + // Put back every parked base that a formula added or changed since the last round could + // match, so it re-expands in this round. This is the round in which an un-parked copy + // would first see that formula as new (see the comment on the parking field). wakeParkedBases(); /* @@ -464,13 +409,8 @@ private void computeNextRuleApp(ImmutableHeap<@NonNull RuleAppContainer> further */ final ImmutableList further = minRuleAppContainer.createFurtherApps(goal); - // Empty assumes yield (the re-expansion is just the re-costed base itself, with - // the now-current age): if the base is effectively indexable, park it instead - // of - // re-adding so it stops being re-popped every round. Park further.head() (the - // freshly re-costed container) so the parked age advances exactly as the - // non-parked base's would, keeping later assumes matches from re-deriving stale - // instances. A non-indexable base falls through and is re-added unchanged. + // The re-expansion produced only the re-costed base itself: park it if it + // can be keyed, re-add it unchanged otherwise (see ParkedBases#park). if (further.size() == 1 && further.head() instanceof TacletAppContainer base && !base.getTacletApp().assumesInstantionsComplete() @@ -505,187 +445,61 @@ && park(base)) { } // --------------------------------------------------------------------------------------------- - // Assumes-base parking (see parkedByOp) + // Assumes-base parking (see the parking field) // --------------------------------------------------------------------------------------------- /** - * Park an assumes-incomplete base, indexing it under the top operator(s) of its - * {@code \assumes} - * formulas so it can be woken when a matching formula appears. + * Set the given base aside; see {@link ParkedBases#park}. * - * @param base the re-costed base container to park (carries the current age) - * @return {@code true} if the base was parked; {@code false} if it is not effectively indexable - * (an unbound-generic {@code \assumes} top), in which case the caller must keep it in - * the - * active queue + * @return {@code true} if the base was parked, {@code false} if it cannot be parked and the + * caller must keep it in the queue */ private boolean park(TacletAppContainer base) { - final List ops = assumesWakeOps(base); - if (ops == null) { - return false; - } - if (parkedByOp == null) { - parkedByOp = new LinkedHashMap<>(); - } - for (Operator op : ops) { - Collection bucket = parkedByOp.get(op); - if (bucket == null) { - bucket = new ArrayList<>(4); - parkedByOp.put(op, bucket); - } - bucket.add(base); - // unindexParked removes by value -- O(n) on a list. A few operators can collect - // thousands of parked bases (e.g. the update operator on long straight-line proofs), - // which would make wake/unpark O(n^2). Once a bucket grows past the threshold, switch - // it - // to a LinkedHashSet for O(1) removal; small buckets (the vast majority) stay - // ArrayLists - // for the memory saving. Both preserve insertion order, so the woken set is unchanged. - if (bucket.size() == BUCKET_SET_THRESHOLD && bucket instanceof ArrayList) { - parkedByOp.put(op, new LinkedHashSet<>(bucket)); - } - } - return true; + return parking.park(base, goal); } /** - * Re-insert into the active queue every parked base waiting on an operator that was added or - * modified since the previous round (see {@link #pendingWakeOps}). Woken bases are collected in - * insertion order (deterministic) and removed from all their index buckets. + * Put back into the queue every parked base that a formula changed since the previous round + * could match; see {@link ParkedBases#drainWoken()}. */ private void wakeParkedBases() { - if (pendingWakeOps == null) { - return; - } - if (parkedByOp != null && !parkedByOp.isEmpty()) { - LinkedHashSet woken = null; - for (Operator op : pendingWakeOps) { - final Collection bucket = parkedByOp.get(op); - if (bucket != null) { - if (woken == null) { - woken = new LinkedHashSet<>(); - } - woken.addAll(bucket); - } - } - if (woken != null) { - for (RuleAppContainer c : woken) { - unindexParked(c); - } - var time = System.nanoTime(); - try { - queue = queue.insert(woken.iterator()); - } finally { - PERF_QUEUE_OPS.addAndGet(System.nanoTime() - time); - } + final Collection woken = parking.drainWoken(); + if (!woken.isEmpty()) { + var time = System.nanoTime(); + try { + queue = queue.insert(woken.iterator()); + } finally { + PERF_QUEUE_OPS.addAndGet(System.nanoTime() - time); } } - pendingWakeOps.clear(); - } - - /** Remove a woken container from every operator bucket it was parked under. */ - private void unindexParked(RuleAppContainer c) { - if (parkedByOp == null || !(c instanceof TacletAppContainer tac)) { - return; - } - final List ops = assumesWakeOps(tac); - if (ops == null) { - return; - } - for (Operator op : ops) { - final Collection bucket = parkedByOp.get(op); - if (bucket != null) { - bucket.remove(c); - if (bucket.isEmpty()) { - parkedByOp.remove(op); - } - } - } - } - - /** - * The concrete top operator(s) of the {@code \assumes} formulas of the given base, resolved - * through the find-match's schema-variable instantiations. - * - * @return the wake operators, or {@code null} if the base is not effectively indexable - * -- i.e. some {@code \assumes} formula has a top that is an unbound schema variable - * (it - * would match any formula, so no precise wake operator exists) or has no - * {@code \assumes} - * formulas at all - */ - private static @Nullable List assumesWakeOps(TacletAppContainer base) { - final NoPosTacletApp app = base.getTacletApp(); - final Sequent assumesSeq = app.taclet().assumesSequent(); - if (assumesSeq.isEmpty()) { - return null; - } - final SVInstantiations insts = app.instantiations(); - final List ops = new ArrayList<>(assumesSeq.size()); - for (SequentFormula sf : assumesSeq) { - Operator op = sf.formula().op(); - if (op instanceof SchemaVariable sv) { - final Object inst = insts.getInstantiation(sv); - if (!(inst instanceof JTerm instTerm)) { - return null; // unbound (or non-term) generic top -> not indexable - } - op = instTerm.op(); - if (op instanceof SchemaVariable) { - return null; // still schematic -> not indexable - } - } - ops.add(op); - } - return ops; } /** - * Record, for the next round's wake-up, the top operators of every formula added or modified by - * this sequent change. The assumes matcher strips the update context before matching, so the - * whole update-prefix spine of each changed formula is recorded -- a sound superset of the - * operators a parked base could match (see {@link #parkedByOp}). Called by {@code Goal} on - * every sequent change. + * Called by {@code Goal} whenever it adds or changes a formula in the sequent. Records the + * wake keys of each such formula (see {@link ParkedBases#recordWakeKeysOf}), so that + * {@link #wakeParkedBases()} can wake the matching bases at the start of the next round. *

- * Determinism invariant (see the class Javadoc): these events must be - * delivered - * in the goal's own order. The wake operators recorded here decide which parked bases - * are re-inserted next round, and thus the birth-age of the resulting candidates; reordering or - * coalescing {@code sequentChanged} deliveries across a goal's history would change wake timing - * and silently diverge the proof. + * The calls for one goal must arrive in the order in which that goal changed its sequent. + * These records decide which bases are woken in which round, and so, as the class comment + * explains, they decide the proof. Combining or reordering the calls would change the proof. */ public void sequentChanged(SequentChangeInfo sci) { - recordWakeOps(sci.addedFormulas(true)); - recordWakeOps(sci.addedFormulas(false)); - recordModifiedWakeOps(sci.modifiedFormulas(true)); - recordModifiedWakeOps(sci.modifiedFormulas(false)); + recordWakeKeys(sci.addedFormulas(true), true); + recordWakeKeys(sci.addedFormulas(false), false); + recordModifiedWakeKeys(sci.modifiedFormulas(true), true); + recordModifiedWakeKeys(sci.modifiedFormulas(false), false); } - private void recordWakeOps(ImmutableList added) { + private void recordWakeKeys(ImmutableList added, boolean inAntecedent) { for (SequentFormula sf : added) { - recordSpineOps(sf.formula()); + parking.recordWakeKeysOf(sf.formula(), inAntecedent); } } - private void recordModifiedWakeOps(ImmutableList modified) { + private void recordModifiedWakeKeys(ImmutableList modified, + boolean inAntecedent) { for (FormulaChangeInfo fci : modified) { - recordSpineOps(fci.newFormula().formula()); - } - } - - /** Add the operators along a formula's update-application spine to {@link #pendingWakeOps}. */ - private void recordSpineOps(org.key_project.logic.Term formula) { - if (pendingWakeOps == null) { - pendingWakeOps = new LinkedHashSet<>(); - } - org.key_project.logic.Term t = formula; - while (true) { - final Operator op = t.op(); - pendingWakeOps.add(op); - if (op instanceof UpdateApplication && t instanceof JTerm jt) { - t = UpdateApplication.getTarget(jt); - } else { - break; - } + parking.recordWakeKeysOf(fci.newFormula().formula(), inAntecedent); } } @@ -696,36 +510,20 @@ public RuleApplicationManager copy() { } /** - * Copies this manager for a split goal. The parking/wake structures MUST be - * deep-copied - * (fresh outer map/set + fresh per-operator buckets), so each split sibling parks and wakes - * independently: sharing them would let one sibling's wake shift another sibling's candidate - * birth-ages and silently change that branch's proof. This deep copy is the enforcement of the - * goal-local determinism invariant documented on the class; see also - * {@code QueueRuleApplicationManagerParkingLocalityTest}. The contained - * {@link RuleAppContainer}s - * and {@link Operator}s are immutable and may be shared. + * Copies this manager when its goal splits into two. Each copy gets its own parking state + * ({@link ParkedBases#copy()}), so that the two new goals park and wake independently. If + * they shared this state, one goal waking a base would change the round in which it enters + * the other goal's queue, and so change that goal's proof (see the class comment). The + * stored {@link RuleAppContainer}s are never modified in place, so the copies may share + * them. {@code QueueRuleApplicationManagerParkingLocalityTest} checks that this copy is + * deep enough. */ @Override public Object clone() { QueueRuleApplicationManager res = new QueueRuleApplicationManager(); res.queue = queue; res.previousMinimum = previousMinimum; - // deep-copy the goal-local parking structures (see the method Javadoc and the class-level - // determinism invariant); the contained containers and operators are immutable and shared - if (parkedByOp != null) { - final LinkedHashMap> copy = - new LinkedHashMap<>(parkedByOp.size()); - for (Map.Entry> e : parkedByOp.entrySet()) { - final Collection v = e.getValue(); - copy.put(e.getKey(), - v instanceof LinkedHashSet ? new LinkedHashSet<>(v) : new ArrayList<>(v)); - } - res.parkedByOp = copy; - } - if (pendingWakeOps != null) { - res.pendingWakeOps = new LinkedHashSet<>(pendingWakeOps); - } + res.parking = parking.copy(); return res; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java index c98ad039e22..33b61e672f1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java @@ -75,7 +75,7 @@ public final int compareTo(RuleAppContainer o) { // comes from cost (above), which the tie-break never sees. Cost (aging) and this tie-break // together keep the multi-worker search deterministic -- the tie-break alone is not the // whole story, so a change that leaves this method intact can still reorder the proof by - // shifting costs/ages (e.g. by changing candidate birth timing). + // shifting costs/ages (e.g. by changing the round in which a candidate is created). return compareByContent(this, o); } diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/ParkedBasesRuntimeTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/ParkedBasesRuntimeTest.java new file mode 100644 index 00000000000..ea828a459fa --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/ParkedBasesRuntimeTest.java @@ -0,0 +1,153 @@ +/* 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.Collection; +import java.util.Iterator; +import java.util.List; + +import de.uka.ilkd.key.control.DefaultUserInterfaceControl; +import de.uka.ilkd.key.control.KeYEnvironment; +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.op.LogicVariable; +import de.uka.ilkd.key.rule.NoPosTacletApp; +import de.uka.ilkd.key.rule.Taclet; +import de.uka.ilkd.key.strategy.ParkedBases.WakeKey; +import de.uka.ilkd.key.strategy.ParkedBases.WakeKind; +import de.uka.ilkd.key.util.HelperClassForTests; + +import org.key_project.logic.Name; +import org.key_project.logic.op.sv.SchemaVariable; +import org.key_project.logic.sort.Sort; +import org.key_project.prover.strategy.costbased.NumberRuleAppCost; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Checks the runtime cycle of {@link ParkedBases} with real taclet applications: a base parked + * under its derived keys is returned by {@link ParkedBases#drainWoken()} exactly once when a + * matching formula is recorded, leaves the parked map through the key recomputation of the + * unindexing, and the woken bases of one round come out one {@link WakeKind} at a time in the + * fixed wake order, which the queue turns into the proof-relevant insertion order. The key + * derivation itself and the park-versus-wake agreement on formula shapes are covered by + * {@link QueueRuleApplicationManagerWakeKeyTest} and + * {@link QueueRuleApplicationManagerSelfWakeTest}. + */ +public class ParkedBasesRuntimeTest { + + private static KeYEnvironment env; + private static Services services; + private static TermBuilder tb; + + @BeforeAll + static void setUp() throws Exception { + env = HelperClassForTests.createKeYEnvironment(); + services = env.getServices(); + tb = services.getTermBuilder(); + } + + @AfterAll + static void tearDown() { + if (env != null) { + env.dispose(); + } + } + + @Test + void wokenBaseIsDrainedOnceAndReleased() { + final ParkedBases parking = new ParkedBases(); + final TacletAppContainer base = container("applyEq", "s", tb.zTerm("42")); + final WakeKey key = park(parking, base); + assertEquals(WakeKind.ARG_HASH, key.kind()); + + final JTerm completer = tb.equals(tb.zTerm("42"), tb.zTerm("7")); + parking.recordWakeKeysOf(completer, key.inAntecedent()); + final Collection woken = parking.drainWoken(); + assertEquals(1, woken.size(), "the parked base must be woken"); + assertSame(base, woken.iterator().next(), "the woken base is the parked one"); + assertTrue(parking.parkedMapForTests().isEmpty(), + "unindexing recomputes the base's keys and releases it from the map"); + + parking.recordWakeKeysOf(completer, key.inAntecedent()); + assertTrue(parking.drainWoken().isEmpty(), + "with nothing parked a second change wakes nothing"); + } + + @Test + void unmatchedChangesWakeNothing() { + final ParkedBases parking = new ParkedBases(); + final TacletAppContainer base = container("applyEq", "s", tb.zTerm("42")); + final WakeKey key = park(parking, base); + + // the right formula on the wrong side, then a structurally different one on the right side + parking.recordWakeKeysOf(tb.equals(tb.zTerm("42"), tb.zTerm("7")), !key.inAntecedent()); + parking.recordWakeKeysOf(tb.equals(tb.add(tb.zTerm("4"), tb.zTerm("2")), tb.zTerm("7")), + key.inAntecedent()); + assertTrue(parking.drainWoken().isEmpty(), "no recorded change matches the parked key"); + assertEquals(1, parking.parkedMapForTests().size(), "the base stays parked"); + } + + @Test + void drainCollectsOneKindAtATimeInWakeOrder() { + final Sort intSort = services.getTypeConverter().getIntegerLDT().targetSort(); + final LogicVariable x = new LogicVariable(new Name("runtimeX"), intSort); + final JTerm phi = tb.all(x, tb.equals(tb.var(x), tb.var(x))); + + final ParkedBases parking = new ParkedBases(); + final TacletAppContainer argHashBase = container("applyEq", "s", tb.zTerm("42")); + final TacletAppContainer wholeHashBase = container("replace_known_left", "b", phi); + // Parked in the opposite of the wake order, so a passing test cannot be an accident of + // insertion: ARG_HASH is collected before WHOLE_HASH regardless. + final WakeKey wholeKey = park(parking, wholeHashBase); + final WakeKey argKey = park(parking, argHashBase); + assertEquals(WakeKind.WHOLE_HASH, wholeKey.kind()); + assertEquals(WakeKind.ARG_HASH, argKey.kind()); + + parking.recordWakeKeysOf(tb.equals(tb.zTerm("42"), tb.zTerm("7")), argKey.inAntecedent()); + parking.recordWakeKeysOf(phi, wholeKey.inAntecedent()); + final Collection woken = parking.drainWoken(); + assertEquals(2, woken.size(), "both bases must wake"); + final Iterator it = woken.iterator(); + assertSame(argHashBase, it.next(), "the ARG_HASH kind is collected first"); + assertSame(wholeHashBase, it.next(), "the WHOLE_HASH kind is collected last"); + assertNotNull(parking.parkedMapForTests()); + assertTrue(parking.parkedMapForTests().isEmpty(), "both bases left the map"); + } + + /** Parks the container under its single derived key and returns that key. */ + private static WakeKey park(ParkedBases parking, TacletAppContainer base) { + final List keys = ParkedBases.parkKeys(base.getTacletApp()); + assertNotNull(keys, "expected the application to be parkable"); + assertEquals(1, keys.size(), "expected one precise park key"); + parking.parkForTests(keys.get(0), base); + return keys.get(0); + } + + /** A container over the shipped taclet with one schema variable bound to the given term. */ + private static TacletAppContainer container(String tacletName, String svName, JTerm term) { + final Taclet taclet = env.getInitConfig().lookupActiveTaclet(new Name(tacletName)); + assertNotNull(taclet, "shipped taclet " + tacletName + " not found"); + NoPosTacletApp app = NoPosTacletApp.createNoPosTacletApp(taclet); + SchemaVariable sv = null; + for (SchemaVariable v : app.uninstantiatedVars()) { + if (v.name().toString().equals(svName)) { + sv = v; + } + } + assertNotNull(sv, "schema variable " + svName + " not found in " + tacletName); + final NoPosTacletApp bound = + (NoPosTacletApp) app.addCheckedInstantiation(sv, term, services, true); + return new NoFindTacletAppContainer(bound, NumberRuleAppCost.getZeroCost(), true, + NumberRuleAppCost.getZeroCost(), -1); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerParkingLocalityTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerParkingLocalityTest.java index 1506760a963..3a843c9df1b 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerParkingLocalityTest.java +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerParkingLocalityTest.java @@ -3,15 +3,12 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; import de.uka.ilkd.key.logic.op.Junctor; - -import org.key_project.logic.op.Operator; +import de.uka.ilkd.key.strategy.ParkedBases.WakeKey; +import de.uka.ilkd.key.strategy.ParkedBases.WakeKind; import org.junit.jupiter.api.Test; @@ -21,69 +18,72 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Pins the goal-local determinism invariant of {@link QueueRuleApplicationManager} (see its class - * Javadoc): cloning a manager for a split goal must deep-copy the assumes-base - * parking/wake - * structures ({@code parkedByOp} / {@code pendingWakeOps}), so split siblings park and wake - * independently. Sharing them would let one sibling's wake shift another sibling's candidate - * birth-ages and silently change that branch's proof (a divergence no closure-only test would - * catch). This test guards against a future "shared wake cache" / cross-goal-reuse regression. + * Checks a property that {@link QueueRuleApplicationManager} relies on for reproducible proofs + * (see its class comment): when a goal splits into two, copying its parking state + * ({@link ParkedBases#copy()}) must give each copy its own map, buckets, and pending change set, + * so the two goals set candidates aside and put them back independently. If they shared this + * state, one goal putting a candidate back would change the round in which it enters the other + * goal's queue, and so change that goal's proof. Such a change would not make any test fail + * that only checks whether a proof closes, which is why this property is checked directly. */ public class QueueRuleApplicationManagerParkingLocalityTest { @Test - void cloneDeepCopiesParkingStructuresSoSiblingsAreIndependent() throws Exception { - final QueueRuleApplicationManager orig = new QueueRuleApplicationManager(); + void copyDeepCopiesParkingStructuresSoSiblingsAreIndependent() { + final ParkedBases orig = new ParkedBases(); - // Populate the (private) goal-local parking structures with sample state. Junctor constants - // are convenient interned Operators; the bucket contents are irrelevant to the deep-copy. - final LinkedHashMap> parked = new LinkedHashMap<>(); - final Collection bucket = new ArrayList<>(); - parked.put(Junctor.AND, bucket); - final LinkedHashSet wake = new LinkedHashSet<>(); - wake.add(Junctor.OR); - set(orig, "parkedByOp", parked); - set(orig, "pendingWakeOps", wake); + // Populate the parking structures with sample state. A WakeKey over Junctor constants + // (convenient interned operators) is a valid key; the bucket contents are irrelevant to + // the deep-copy. + final WakeKey key = new WakeKey(WakeKind.OP, true, Junctor.AND, null); + orig.parkForTests(key, new StubRuleAppContainer()); + final Collection bucket = orig.parkedMapForTests().get(key); + orig.pendingWakeKeys = new LinkedHashSet<>(); + orig.pendingWakeKeys.add(new WakeKey(WakeKind.OP, true, Junctor.OR, null)); - final QueueRuleApplicationManager copy = (QueueRuleApplicationManager) orig.clone(); + final ParkedBases copy = orig.copy(); - final Object copyParked = get(copy, "parkedByOp"); - final Object copyWake = get(copy, "pendingWakeOps"); - assertNotNull(copyParked, "clone must copy parkedByOp"); - assertNotNull(copyWake, "clone must copy pendingWakeOps"); + assertNotNull(copy.parkedMapForTests(), "copy must carry the parked map"); + assertNotNull(copy.pendingWakeKeys, "copy must carry the pending change set"); // Deep copy: the split sibling must not share the outer structures. - assertNotSame(parked, copyParked, "parkedByOp must be deep-copied, not shared"); - assertNotSame(wake, copyWake, "pendingWakeOps must be deep-copied, not shared"); - @SuppressWarnings("unchecked") - final Collection copyBucket = - ((LinkedHashMap>) copyParked).get(Junctor.AND); - assertNotSame(bucket, copyBucket, "the per-operator parking bucket must be deep-copied"); + assertNotSame(orig.parkedMapForTests(), copy.parkedMapForTests(), + "the parked map must be deep-copied, not shared"); + assertNotSame(orig.pendingWakeKeys, copy.pendingWakeKeys, + "the pending change set must be deep-copied, not shared"); + final Collection copyBucket = copy.parkedMapForTests().get(key); + assertNotSame(bucket, copyBucket, "the parking bucket must be deep-copied"); - // Independence: a park/wake recorded on one sibling after the split must not appear on the - // other -- this is what keeps each branch's candidate birth-ages (and thus its proof) - // its own. - rawAdd(bucket, new Object()); - wake.add(Junctor.IMP); - assertTrue(copyBucket.isEmpty(), + // Independence: a park or wake recorded on one sibling after the split must not appear on + // the other. This is what keeps the round in which a candidate enters each branch's queue, + // and with it that branch's proof, independent of the other branch. + orig.parkForTests(key, new StubRuleAppContainer()); + orig.pendingWakeKeys.add(new WakeKey(WakeKind.OP, true, Junctor.IMP, null)); + assertEquals(1, copyBucket.size(), "a sibling's parked bucket must not see a park added to the other sibling"); - assertEquals(1, ((LinkedHashSet) copyWake).size(), - "a sibling's wake set must not see an op recorded on the other sibling"); - } + assertEquals(1, copy.pendingWakeKeys.size(), + "a sibling's wake set must not see a key recorded on the other sibling"); - private static void set(Object target, String field, Object value) throws Exception { - final Field f = QueueRuleApplicationManager.class.getDeclaredField(field); - f.setAccessible(true); - f.set(target, value); - } - - private static Object get(Object target, String field) throws Exception { - final Field f = QueueRuleApplicationManager.class.getDeclaredField(field); - f.setAccessible(true); - return f.get(target); - } + // The per-head counts must be sibling-local as well: they gate which wake keys a + // changed formula records, so a shared array would let one sibling's parks make the + // other compute keys for bases it does not hold. + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final var tb = services.getTermBuilder(); + final var orFormula = tb.or(tb.tt(), tb.ff()); + orig.parkForTests(new WakeKey(WakeKind.OP, true, Junctor.OR, null), + new StubRuleAppContainer()); + copy.recordWakeKeysOf(orFormula, true); + assertTrue(copy.pendingWakeKeys == null || copy.pendingWakeKeys.size() == 1, + "a sibling must not record keys for heads only the other sibling parked under"); + orig.recordWakeKeysOf(orFormula, true); + assertTrue(orig.pendingWakeKeys.stream() + .anyMatch(k -> ((WakeKey) k).head() == Junctor.OR), + "the parking sibling must record the key for its own parked head"); - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static void rawAdd(Collection c, Object o) { - c.add(o); + // The manager-level clone must route through the same deep copy. + final QueueRuleApplicationManager manager = new QueueRuleApplicationManager(); + final QueueRuleApplicationManager managerCopy = + (QueueRuleApplicationManager) manager.clone(); + assertNotNull(managerCopy); + assertTrue(managerCopy != manager); } } diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerSelfWakeTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerSelfWakeTest.java new file mode 100644 index 00000000000..be521ec29a3 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerSelfWakeTest.java @@ -0,0 +1,255 @@ +/* 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.List; +import java.util.Set; + +import de.uka.ilkd.key.control.DefaultUserInterfaceControl; +import de.uka.ilkd.key.control.KeYEnvironment; +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.ldt.JavaDLTheory; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.ProgramElementName; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.op.FormulaSV; +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.op.LocationVariable; +import de.uka.ilkd.key.logic.op.LogicVariable; +import de.uka.ilkd.key.logic.op.SchemaVariableFactory; +import de.uka.ilkd.key.logic.op.TermSV; +import de.uka.ilkd.key.logic.op.UpdateApplication; +import de.uka.ilkd.key.logic.op.UpdateSV; +import de.uka.ilkd.key.proof.calculus.JavaDLSequentKit; +import de.uka.ilkd.key.rule.NoPosTacletApp; +import de.uka.ilkd.key.rule.RewriteTaclet; +import de.uka.ilkd.key.rule.Taclet; +import de.uka.ilkd.key.rule.tacletbuilder.RewriteTacletBuilder; +import de.uka.ilkd.key.rule.tacletbuilder.RewriteTacletGoalTemplate; +import de.uka.ilkd.key.util.HelperClassForTests; + +import org.key_project.logic.Name; +import org.key_project.logic.op.Function; +import org.key_project.logic.op.sv.SchemaVariable; +import org.key_project.logic.sort.Sort; +import org.key_project.prover.sequent.SequentFormula; +import org.key_project.util.collection.ImmutableList; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Checks, for the two hash-based {@code WakeKind}s, that parking and waking agree on concrete + * instances: a base parked under a hash key must be found by the wake keys of every formula the + * matcher would accept for it. The descriptor-space test + * ({@link QueueRuleApplicationManagerWakeKeyTest}) checks the shape of park keys for all shipped + * taclets, but it cannot check this agreement, because the hash keys only exist once the main + * match has fixed a schema variable to a concrete term. Here real taclets are instantiated by + * hand and the two sides are compared directly. + */ +public class QueueRuleApplicationManagerSelfWakeTest { + + private static KeYEnvironment env; + private static Services services; + private static TermBuilder tb; + + @BeforeAll + static void setUp() throws Exception { + env = HelperClassForTests.createKeYEnvironment(); + services = env.getServices(); + tb = services.getTermBuilder(); + } + + @AfterAll + static void tearDown() { + if (env != null) { + env.dispose(); + } + } + + /** + * {@code applyEq} waits for an equality whose first argument is the term the main match + * bound to {@code s}. Its {@link WakeKind#ARG_HASH} park key must be produced as a wake key + * by exactly the equalities with that first argument, and not by others. + */ + @Test + void argHashParkKeyIsWokenByMatchingEquality() throws Exception { + final NoPosTacletApp app = + instantiated("applyEq", "s", tb.zTerm("42")); + final ParkedBases.WakeKey parkKey = singleParkKey(app, "ARG_HASH"); + + assertTrue( + wakeKeysOf(tb.equals(tb.zTerm("42"), tb.zTerm("7")), parkKey).contains(parkKey), + "an equality with the bound first argument must wake the base"); + // The negative control must differ from 42 in structure, not only in the digits: + // hashCodeModRenaming folds the structure and sorts of a term but not function names + // (it may only reject what matching modulo renaming would reject), so the literals 42 + // and 43 share a hash and waking on 43 = 7 would be a designed, harmless over-wake. + assertFalse( + wakeKeysOf(tb.equals(tb.add(tb.zTerm("4"), tb.zTerm("2")), tb.zTerm("7")), parkKey) + .contains(parkKey), + "an equality with a structurally different first argument must not wake the base"); + } + + /** + * {@code replace_known_left} waits for a formula equal to the one the main match bound to + * {@code b}, up to renaming of bound variables. Its {@link WakeKind#WHOLE_HASH} park key + * must be produced as a wake key by that formula, by a renamed variant of it, and by the + * formula wrapped in an update (the matcher removes leading updates before it matches, so + * parking and waking must compare the formula without them). + */ + @Test + void wholeHashParkKeyIsWokenByEqualModRenamingFormula() throws Exception { + final Sort intSort = services.getTypeConverter().getIntegerLDT().targetSort(); + final LogicVariable x = new LogicVariable(new Name("selfWakeX"), intSort); + final LogicVariable y = new LogicVariable(new Name("selfWakeY"), intSort); + final JTerm phi = tb.all(x, tb.equals(tb.var(x), tb.var(x))); + final JTerm phiRenamed = tb.all(y, tb.equals(tb.var(y), tb.var(y))); + + final NoPosTacletApp app = instantiated("replace_known_left", "b", phi); + final ParkedBases.WakeKey parkKey = singleParkKey(app, "WHOLE_HASH"); + + assertTrue(wakeKeysOf(phi, parkKey).contains(parkKey), + "the bound formula itself must wake the base"); + assertTrue(wakeKeysOf(phiRenamed, parkKey).contains(parkKey), + "a variant of the formula with renamed bound variables must wake the base"); + + final LocationVariable pv = + new LocationVariable(new ProgramElementName("selfWakeVar"), intSort); + final JTerm wrapped = tb.apply(tb.elementary(pv, tb.zTerm("1")), phi); + assertTrue(wakeKeysOf(wrapped, parkKey).contains(parkKey), + "the formula wrapped in an update must wake the base"); + + assertFalse( + wakeKeysOf(phi, parkKey, !parkKey.inAntecedent()).contains(parkKey), + "a formula on the other side of the sequent must not wake the base: assumes" + + " formulas only match formulas of their own side"); + + final JTerm other = tb.all(x, tb.equals(tb.var(x), tb.zTerm("0"))); + assertFalse(wakeKeysOf(other, parkKey).contains(parkKey), + "a different formula must not wake the base"); + } + + /** + * Wake keys are only computed for kinds under which some base is parked. With nothing + * parked, a changed formula must record no keys at all, and with only an + * {@link WakeKind#ARG_HASH} base parked it must record only keys of that kind. This is + * what keeps proofs that park nothing free of the hash computations, which walk the whole + * changed formula. + */ + @Test + void wakeKeysAreOnlyRecordedForKindsWithParkedBases() throws Exception { + final ParkedBases empty = new ParkedBases(); + empty.recordWakeKeysOf(tb.equals(tb.zTerm("1"), tb.zTerm("2")), true); + assertTrue(empty.pendingWakeKeys == null || empty.pendingWakeKeys.isEmpty(), + "with nothing parked, no wake keys may be recorded"); + + final NoPosTacletApp app = instantiated("applyEq", "s", tb.zTerm("42")); + final ParkedBases.WakeKey parkKey = singleParkKey(app, "ARG_HASH"); + for (Object key : wakeKeysOf(tb.equals(tb.zTerm("42"), tb.zTerm("7")), parkKey)) { + assertEquals("ARG_HASH", ((ParkedBases.WakeKey) key).kind().toString(), + "only keys of kinds with parked bases may be recorded"); + } + } + + /** + * A base whose {@code \assumes} first argument is an update application, as in + * {@code \assumes(p({u}x) ==>)}, is parked under an {@link WakeKind#ARG_OP} key whose datum + * is the update application operator, and a formula whose first argument is a concrete + * update application produces exactly that wake key. Argument positions are matched as + * written, so the update is part of what both sides observe; only leading updates of the + * formula itself are stripped. No shipped taclet has this shape, so the taclet is built + * here the way a user-loaded rule would introduce it. + */ + @Test + void updateApplicationArgumentParkKeyIsWokenByUpdateArgumentFormula() { + final Sort intSort = services.getTypeConverter().getIntegerLDT().targetSort(); + final Function p = + new JFunction(new Name("selfWakeUpdArgP"), JavaDLTheory.FORMULA, intSort); + final UpdateSV u = SchemaVariableFactory.createUpdateSV(new Name("selfWakeU")); + final TermSV x = SchemaVariableFactory.createTermSV(new Name("selfWakeXsv"), intSort); + final JTerm pattern = tb.func(p, tb.apply(tb.var(u), tb.var(x))); + + final FormulaSV find = SchemaVariableFactory.createFormulaSV(new Name("selfWakeFind")); + final RewriteTacletBuilder builder = new RewriteTacletBuilder<>(); + builder.setName(new Name("selfWakeUpdArgTaclet")); + builder.setFind(tb.var(find)); + builder.setAssumesSequent(JavaDLSequentKit.createAnteSequent( + ImmutableList.singleton(new SequentFormula(pattern)))); + builder.addTacletGoalTemplate( + new RewriteTacletGoalTemplate(JavaDLSequentKit.getInstance().getEmptySequent(), + ImmutableList.nil(), tb.var(find))); + + final NoPosTacletApp app = + NoPosTacletApp.createNoPosTacletApp(builder.getRewriteTaclet()); + final ParkedBases.WakeKey parkKey = singleParkKey(app, "ARG_OP"); + assertEquals(p, parkKey.head(), "the key's head must be the pattern's concrete top"); + assertTrue(parkKey.datum() instanceof UpdateApplication, + "the key's datum must be the update application family, but is " + parkKey.datum()); + assertTrue(parkKey.inAntecedent(), "the assumes formula sits in the antecedent"); + + final LocationVariable pv = + new LocationVariable(new ProgramElementName("selfWakeUpdVar"), intSort); + final JTerm candidate = + tb.func(p, tb.apply(tb.elementary(pv, tb.zTerm("1")), tb.zTerm("3"))); + assertTrue(wakeKeysOf(candidate, parkKey).contains(parkKey), + "a formula with an update application as first argument must wake the base"); + assertFalse(wakeKeysOf(tb.func(p, tb.zTerm("5")), parkKey).contains(parkKey), + "a formula whose first argument carries no update must not wake the base"); + assertFalse(wakeKeysOf(candidate, parkKey, false).contains(parkKey), + "a formula on the other side of the sequent must not wake the base"); + } + + /** The shipped taclet of the given name with one schema variable bound to the given term. */ + private static NoPosTacletApp instantiated(String tacletName, String svName, JTerm term) + throws Exception { + final Taclet taclet = env.getInitConfig().lookupActiveTaclet(new Name(tacletName)); + assertNotNull(taclet, "shipped taclet " + tacletName + " not found"); + NoPosTacletApp app = NoPosTacletApp.createNoPosTacletApp(taclet); + SchemaVariable sv = null; + for (SchemaVariable v : app.uninstantiatedVars()) { + if (v.name().toString().equals(svName)) { + sv = v; + } + } + assertNotNull(sv, "schema variable " + svName + " not found in " + tacletName); + return (NoPosTacletApp) app.addCheckedInstantiation(sv, term, services, true); + } + + /** The single park key of the given application, asserting its {@code WakeKind}. */ + private static ParkedBases.WakeKey singleParkKey(NoPosTacletApp app, String expectedKind) { + final List keys = ParkedBases.parkKeys(app); + assertNotNull(keys, "expected the application to be parkable"); + assertEquals(1, keys.size(), "expected one precise park key"); + final ParkedBases.WakeKey key = keys.get(0); + assertEquals(expectedKind, key.kind().toString()); + return key; + } + + /** + * The wake keys recorded for the given changed formula while one base is parked under the + * given key. The park is needed because keys of a kind without parked bases are not + * computed at all (see {@link ParkedBases#recordWakeKeysOf}). + */ + private static Set wakeKeysOf(JTerm formula, ParkedBases.WakeKey parkedUnder) { + return wakeKeysOf(formula, parkedUnder, parkedUnder.inAntecedent()); + } + + /** As above, with the changed formula on the given side of the sequent. */ + private static Set wakeKeysOf(JTerm formula, ParkedBases.WakeKey parkedUnder, + boolean inAntecedent) { + final ParkedBases parking = new ParkedBases(); + parking.parkForTests(parkedUnder, new StubRuleAppContainer()); + parking.recordWakeKeysOf(formula, inAntecedent); + final Set keys = parking.pendingWakeKeys; + assertNotNull(keys, "recording a formula must create wake keys"); + return keys; + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerWakeKeyTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerWakeKeyTest.java new file mode 100644 index 00000000000..ac4184c4384 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/QueueRuleApplicationManagerWakeKeyTest.java @@ -0,0 +1,178 @@ +/* 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.List; + +import de.uka.ilkd.key.control.DefaultUserInterfaceControl; +import de.uka.ilkd.key.control.KeYEnvironment; +import de.uka.ilkd.key.logic.op.JModality; +import de.uka.ilkd.key.logic.op.ModalOperatorSV; +import de.uka.ilkd.key.logic.op.ParametricFunctionDecl; +import de.uka.ilkd.key.logic.op.ParametricFunctionInstance; +import de.uka.ilkd.key.logic.op.UpdateApplication; +import de.uka.ilkd.key.rule.NoPosTacletApp; +import de.uka.ilkd.key.rule.Taclet; +import de.uka.ilkd.key.rule.match.vm.JavaMatchPlanBuilder; +import de.uka.ilkd.key.rule.match.vm.VMTacletMatcher; +import de.uka.ilkd.key.util.HelperClassForTests; + +import org.key_project.logic.op.Operator; +import org.key_project.logic.op.sv.SchemaVariable; +import org.key_project.prover.rules.matcher.compiler.PatternKeySource; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Checks that the park keys of {@link ParkedBases#parkKeys} are built from operator families + * for every taclet that ships with KeY. The families come from the taclet's own matcher + * ({@code VMTacletMatcher#assumesKeySource}, fed by the match heads' + * {@code topOperatorDescriptor()}) on the pattern side and from + * {@code JavaMatchPlanBuilder#matchFamilyOf} on the concrete side; a park key and a wake key + * only meet when the two sides agree, which is what these tests pin. A key that contains a raw + * operator the matcher treats more liberally than operator equality can never equal a key + * produced for a concrete sequent formula, so a base stored under it would never be woken. The + * rule {@code referencedObjectIsCreatedRight} had this defect: its {@code \assumes} waits for a + * {@code select} instance with a generic sort argument, which is a different operator than every + * concrete {@code select} instance a sequent can contain. + */ +public class QueueRuleApplicationManagerWakeKeyTest { + + private static KeYEnvironment env; + + @BeforeAll + static void setUp() throws Exception { + env = HelperClassForTests.createKeYEnvironment(); + } + + @AfterAll + static void tearDown() { + if (env != null) { + env.dispose(); + } + } + + /** + * For every shipped taclet with an {@code \assumes} part: all park keys must be stated in + * descriptor space. In particular no key component may be a parametric function instance + * (the descriptor is its base), a modality (the descriptor is its kind), a schema variable, + * or a schematic modality kind. An update application may appear as the datum of an + * {@code ARG_OP} key (argument positions are matched as written), but never as a key's + * head: the top of a candidate is observed with its leading updates stripped, so a head + * naming an update application could never be met. + */ + @Test + void parkKeysOfAllShippedTacletsAreInDescriptorSpace() throws Exception { + int withAssumes = 0; + int parkable = 0; + for (Taclet taclet : env.getInitConfig().getTaclets()) { + if (taclet.assumesSequent().isEmpty()) { + continue; + } + withAssumes++; + final List keys = + ParkedBases.parkKeys(NoPosTacletApp.createNoPosTacletApp(taclet)); + if (keys == null) { + continue; + } + parkable++; + for (Object key : keys) { + assertKeyInDescriptorSpace(taclet, key); + } + } + // guard against silently testing nothing, for example after a rule-base loading change + assertTrue(withAssumes > 100, + "expected the shipped rule base to contain many assumes-taclets, got " + withAssumes); + assertTrue(parkable > 0, "expected at least some parkable assumes-taclets"); + } + + /** + * The defect that motivated descriptors, pinned directly: the park key of + * {@code referencedObjectIsCreatedRight} must use the base function of the + * {@code select<[deltaObject]>} instance, not the instance itself. + */ + @Test + void parametricAssumesFirstArgumentIsKeyedByItsBase() throws Exception { + final Taclet taclet = env.getInitConfig().lookupActiveTaclet( + new org.key_project.logic.Name("referencedObjectIsCreatedRight")); + assertNotNull(taclet, "shipped taclet referencedObjectIsCreatedRight not found"); + final List keys = + ParkedBases.parkKeys(NoPosTacletApp.createNoPosTacletApp(taclet)); + assertNotNull(keys, "expected the taclet to be parkable"); + assertEquals(1, keys.size(), "expected one precise park key"); + final ParkedBases.WakeKey key = (ParkedBases.WakeKey) keys.get(0); + assertEquals("ARG_OP", key.kind().toString()); + final Object datum = key.datum(); + assertTrue(datum instanceof ParametricFunctionDecl, + "the key must hold the base function, but holds " + datum.getClass().getName()); + } + + /** + * The pattern side and the concrete side of the key derivation must agree, or a parked base + * could never be woken: for every shipped {@code \assumes} pattern with a concrete top, the + * family in the matcher's key source ({@code assumesKeySource}) must equal the family + * {@code matchFamilyOf} assigns to the pattern's own operator, and a pattern summarized as + * unkeyable must be exactly one whose operator has no family. (For a pattern operator that + * only stands for itself the two trivially agree; the interesting cases are the family + * operators: parametric functions and modalities.) + */ + @Test + void assumesKeySourcesAgreeWithConcreteFamilies() { + for (Taclet taclet : env.getInitConfig().getTaclets()) { + if (!(taclet.getMatcher() instanceof VMTacletMatcher matcher)) { + continue; + } + for (var sf : taclet.assumesSequent()) { + final org.key_project.logic.Term pattern = sf.formula(); + if (pattern.op() instanceof SchemaVariable) { + continue; + } + final PatternKeySource source = matcher.assumesKeySource(pattern); + final Object family = JavaMatchPlanBuilder.matchFamilyOf(pattern.op()); + final String where = "assumes pattern of " + taclet.name() + ": " + pattern; + if (source instanceof PatternKeySource.ByHead byHead) { + assertEquals(family, byHead.headDescriptor(), + "pattern-side and concrete-side family differ for " + where); + } else { + // An update-application pattern top is deliberately unkeyable although the + // operator has a family: the top position is observed stripped, so a top + // key naming it could never be met (VMTacletMatcher.keySourceFor). + assertTrue(family == null || pattern.op() instanceof UpdateApplication, + "pattern summarized as unkeyable although its operator has the family " + + family + " for " + where); + } + } + } + } + + private static void assertKeyInDescriptorSpace(Taclet taclet, Object rawKey) { + final ParkedBases.WakeKey key = (ParkedBases.WakeKey) rawKey; + assertComponentIsDescriptor(taclet, key.head(), "head"); + // A head naming an update application could never be met: the top of a candidate is + // observed with its leading updates stripped. As an ARG_OP datum it is legitimate, + // because argument positions are matched as written. + assertFalse(key.head() instanceof UpdateApplication, + "update application as head of a park key of " + taclet.name()); + if (key.datum() instanceof Operator datum) { + assertComponentIsDescriptor(taclet, datum, "datum"); + } + } + + private static void assertComponentIsDescriptor(Taclet taclet, Object value, String name) { + assertNotNull(value, name + " of a park key of " + taclet.name()); + final String where = name + " of a park key of " + taclet.name() + ": " + value; + assertFalse(value instanceof ParametricFunctionInstance, + "parametric instance instead of its base as " + where); + assertFalse(value instanceof JModality, "modality instead of its kind as " + where); + assertFalse(value instanceof ModalOperatorSV, "schematic modality kind as " + where); + assertFalse(value instanceof SchemaVariable, "schema variable as " + where); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/StubRuleAppContainer.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/StubRuleAppContainer.java new file mode 100644 index 00000000000..d0116b0c595 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/StubRuleAppContainer.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 de.uka.ilkd.key.proof.Goal; + +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.strategy.costbased.NumberRuleAppCost; +import org.key_project.util.collection.ImmutableList; + +/** A contentless container for tests that drive the parked map without a rule application. */ +final class StubRuleAppContainer extends RuleAppContainer { + + StubRuleAppContainer() { + super(null, NumberRuleAppCost.getZeroCost()); + } + + @Override + public ImmutableList createFurtherApps(Goal goal) { + return ImmutableList.nil(); + } + + @Override + public RuleApp completeRuleApp(Goal goal) { + throw new UnsupportedOperationException("stub"); + } +} diff --git a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/GenericOperatorHead.java b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/GenericOperatorHead.java index f55e5393bab..77165542b82 100644 --- a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/GenericOperatorHead.java +++ b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/GenericOperatorHead.java @@ -38,6 +38,13 @@ public MatchProgram compileHeadCheck() { return (element, mc, services) -> ((Term) element).op() == expected ? mc : null; } + @Override + public Object topOperatorDescriptor() { + // this head accepts exactly one operator (reference identity), so the operator itself + // is the family + return op; + } + @Override public String toString() { return op.name().toString(); diff --git a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchHead.java b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchHead.java index 351fab2e3d2..5026839aa70 100644 --- a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchHead.java +++ b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchHead.java @@ -8,6 +8,8 @@ import org.key_project.prover.rules.matcher.vm.MatchProgram; import org.key_project.prover.rules.matcher.vm.instruction.VMInstruction; +import org.jspecify.annotations.Nullable; + /** * The operator-specific "head" of an {@link OperatorPlan}: it checks the operator of a term and any * operator-specific data (e.g. a modal-operator kind, a parametric function's generic arguments, @@ -37,4 +39,22 @@ public interface MatchHead { * @return the compiled head matcher */ MatchProgram compileHeadCheck(); + + /** + * The operator family this head accepts, as a key for indexing: two terms this head could + * accept must yield equal descriptors, and a term whose top operator is of a different + * family must yield a different one. A head that checks its operator by identity returns the + * operator itself; a head that accepts a whole family (for example every instance of a + * parametric function) returns the family's representative (its base). Returns {@code null} + * if the head cannot be summarized by one family (for example a schematic modality kind, + * which stands for several kinds at once); clients must then not index by this head. + *

+ * This method is deliberately abstract: whoever adds a head for a new operator kind must + * state its family here, next to the matching rule the family has to agree with. See + * {@link MatchPlanBuilder#keySourceFor} for the consumer. + * + * @return the operator family descriptor, or {@code null} if there is none + */ + @Nullable + Object topOperatorDescriptor(); } diff --git a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchPlanBuilder.java b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchPlanBuilder.java index 51002df59cf..2077f62393f 100644 --- a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchPlanBuilder.java +++ b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/MatchPlanBuilder.java @@ -137,6 +137,41 @@ public final MatchPlan planOrThrow(Term pattern) { return core == null ? core : finishPlan(pattern, core); } + /** + * Classifies {@code pattern} into its {@link PatternKeySource} (see there for what the result + * means and why the queue needs it). The classification comes from the same per-operator + * matcher construction ({@link #headFor}) used to match the pattern, so it always agrees with + * which terms the pattern accepts. + * + * @param pattern the pattern to classify + * @return the key source of {@code pattern} + */ + public final PatternKeySource keySourceFor(Term pattern) { + if (pattern.op() instanceof SchemaVariable sv) { + return new PatternKeySource.ByWholeSchemaVariable(sv); + } + final MatchHead head = headFor(pattern); + final Object headDescriptor = head == null ? null : head.topOperatorDescriptor(); + if (headDescriptor == null) { + return PatternKeySource.Unkeyable.INSTANCE; + } + PatternKeySource.FirstArg firstArg = PatternKeySource.FirstArg.None.INSTANCE; + if (pattern.arity() > 0) { + final Term arg = pattern.sub(0); + if (arg.op() instanceof SchemaVariable argSv) { + firstArg = new PatternKeySource.FirstArg.ByArgSchemaVariable(argSv); + } else { + final MatchHead argHead = headFor(arg); + final Object argDescriptor = + argHead == null ? null : argHead.topOperatorDescriptor(); + if (argDescriptor != null) { + firstArg = new PatternKeySource.FirstArg.ByArgHead(argDescriptor); + } + } + } + return new PatternKeySource.ByHead(headDescriptor, firstArg); + } + private @Nullable MatchPlan buildCore(Term pattern) { final Operator op = pattern.op(); diff --git a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/ModalityHead.java b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/ModalityHead.java index 21c8cf81576..60de7211091 100644 --- a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/ModalityHead.java +++ b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/ModalityHead.java @@ -7,6 +7,7 @@ import org.key_project.logic.Term; import org.key_project.logic.op.Modality; +import org.key_project.logic.op.sv.SchemaVariable; import org.key_project.prover.rules.instantiation.MatchResultInfo; import org.key_project.prover.rules.matcher.vm.MatchProgram; import org.key_project.prover.rules.matcher.vm.instruction.CheckNodeKindInstruction; @@ -15,6 +16,8 @@ import org.key_project.prover.rules.matcher.vm.instruction.MatchInstruction; import org.key_project.prover.rules.matcher.vm.instruction.VMInstruction; +import org.jspecify.annotations.Nullable; + /** * Match head for a {@link Modality} {@code \<{ prog }\> post} (the dynamic-logic operator that * carries a program): it matches the operator, the modal kind and the program; the post-condition @@ -27,7 +30,7 @@ */ public final class ModalityHead implements MatchHead { - /** the pattern's modal kind; kept for {@link #toString} only. */ + /** the pattern's modal kind; used by {@link #topOperatorDescriptor} and {@link #toString}. */ private final Modality.Kind patternKind; private final MatchInstruction kindInstr; private final ProgramMatchHook programHook; @@ -70,6 +73,13 @@ public MatchProgram compileHeadCheck() { }; } + @Override + public @Nullable Object topOperatorDescriptor() { + // a modality is accepted when its kind agrees (the program is matched separately), so + // the kind is the family; a schematic kind stands for several kinds and yields none + return patternKind instanceof SchemaVariable ? null : patternKind; + } + @Override public String toString() { return "modality(" + patternKind.name() + ", )"; diff --git a/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/PatternKeySource.java b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/PatternKeySource.java new file mode 100644 index 00000000000..ff9fa0625f3 --- /dev/null +++ b/key.ncore.matcher/src/main/java/org/key_project/prover/rules/matcher/compiler/PatternKeySource.java @@ -0,0 +1,95 @@ +/* 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 org.key_project.prover.rules.matcher.compiler; + +import org.key_project.logic.op.sv.SchemaVariable; + +/** + * For a taclet's {@code \assumes} formula, where a lookup key for it can be taken from. + * + *

+ * The rule-application queue sets aside ("parks") a rule whose {@code \assumes} formula is not + * yet in the sequent, and wakes it when a matching formula appears. To find the waiting rules + * quickly it files each one under a key and looks newly added formulas up by the same key, so + * the key must be one that every formula the {@code \assumes} could match produces. An + * {@code \assumes} formula is a pattern: a fixed term shape in which a schema variable stands + * for an arbitrary term. This type says, for one such pattern, what its key can be built from. + * It is computed by {@link MatchPlanBuilder#keySourceFor} from the same per-operator dispatch + * the matcher runs on, so it always agrees with what the matcher accepts. + * + *

+ * Three cases: + *

    + *
  • {@link ByHead}: the pattern's top operator is a concrete operator. Every term the pattern + * matches then has a top operator of one operator family, named by {@code headDescriptor} (two + * operators of the same family compare equal, see {@link MatchHead#topOperatorDescriptor()}); + * {@code firstArg} optionally adds the family of the first subterm.
  • + *
  • {@link ByWholeSchemaVariable}: the pattern is a single schema variable and matches any + * term, so no key is fixed in advance; a key can only be read off the term the variable is + * instantiated with.
  • + *
  • {@link Unkeyable}: no key can be built, so a client files nothing for this pattern and + * keeps considering the candidate the ordinary way, which never sets a candidate aside wrongly. + * This is also the result for any construct the builder does not recognize, so it is the safe + * default. It arises for example when the top is a schematic modality kind, which stands for + * several concrete kinds at once.
  • + *
+ */ +public sealed interface PatternKeySource { + + /** + * The pattern's top operator is concrete: every term it matches has a top operator of the + * family {@code headDescriptor}, and {@code firstArg} gives the family of the first subterm. + * + * @param headDescriptor the operator family of the pattern's top, never {@code null} + * @param firstArg the family of the pattern's first subterm ({@link FirstArg.None} for a + * pattern without subterms) + */ + record ByHead(Object headDescriptor, FirstArg firstArg) implements PatternKeySource { + } + + /** + * The pattern is a single schema variable and accepts any term; a key can only come from the + * variable's instantiation. + * + * @param sv the pattern's schema variable + */ + record ByWholeSchemaVariable(SchemaVariable sv) implements PatternKeySource { + } + + /** No key can be derived from this pattern. */ + record Unkeyable() implements PatternKeySource { + /** the single instance; the record carries no data */ + public static final Unkeyable INSTANCE = new Unkeyable(); + } + + /** + * The family of a pattern's first subterm, used to tell apart patterns that share a top + * operator but differ one level down. + */ + sealed interface FirstArg { + + /** The pattern has no subterms, or no family can be built for its first subterm. */ + record None() implements FirstArg { + /** the single instance; the record carries no data */ + public static final None INSTANCE = new None(); + } + + /** + * The first subterm's top operator is concrete and belongs to the family + * {@code descriptor}. + * + * @param descriptor the operator family of the first subterm's top, never {@code null} + */ + record ByArgHead(Object descriptor) implements FirstArg { + } + + /** + * The first subterm is a schema variable; a key can only come from its instantiation. + * + * @param sv the first subterm's schema variable + */ + record ByArgSchemaVariable(SchemaVariable sv) implements FirstArg { + } + } +} From b50cfff5bc0ec8d7cdcbc39f73b8fb0d96b21433 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 18 Jul 2026 21:33:21 +0200 Subject: [PATCH 04/15] Order equal-cost formula comparisons by a cached structural name hash The deterministic tie-break on equal-cost rule applications compares sequent formulas by walking their operator names. On large sequents these walks compare the same formulas over and over. JTerm.nameHash() folds the operator names and arities of all subterms into a cached hash and contains nothing else. Unlike hashCode() it excludes term labels, whose hash can embed object identity, so the value is identical across JVM runs, which every key in the proof-search order must be. The formula comparison orders by this hash first and falls back to the name walk only on equal hashes. The comparators are package-visible, so the order property tests call them directly. with AI tooling support --- .../java/de/uka/ilkd/key/logic/TermImpl.java | 22 ++++++++ .../ilkd/key/strategy/RuleAppContainer.java | 50 +++++++++++++------ .../main/java/org/key_project/logic/Term.java | 6 +++ 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java index f40c2462c4f..8cef273f71f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java +++ b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java @@ -89,6 +89,11 @@ private enum ThreeValuedTruth { */ private int hashcodeModRenaming = 0; + /** + * Cached {@link #nameHash()} value. {@code 0} = not yet computed. + */ + private int nameHash = 0; + // ------------------------------------------------------------------------- // constructors // ------------------------------------------------------------------------- @@ -215,6 +220,23 @@ public Sort sort() { } + @Override + public int nameHash() { + if (nameHash == 0) { + int h = 5; + h = h * 31 + op.name().toString().hashCode(); + h = h * 31 + arity(); + for (int i = 0, n = arity(); i < n; i++) { + h = h * 31 + sub(i).nameHash(); + } + if (h == 0) { + h = 1; + } + nameHash = h; + } + return nameHash; + } + @Override public int depth() { if (depth == -1) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java index 33b61e672f1..b8bb3dea267 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/RuleAppContainer.java @@ -53,7 +53,7 @@ protected RuleAppContainer(RuleApp p_app, RuleAppCost p_cost) { @Override public final int compareTo(RuleAppContainer o) { // PRIMARY key: cost. This is where proof-search order is chiefly decided; the cost carries - // the candidate's goal-age (see AgeFeature -- older/younger candidates get different cost), + // the candidate's goal-age (see AgeFeature: older and younger candidates cost differently), // and age in turn depends on WHEN the candidate was born, e.g. when its parked assumes-base // was woken (see QueueRuleApplicationManager's goal-local determinism invariant). Aging is // deterministic per goal, so cost is deterministic per goal. @@ -63,7 +63,7 @@ public final int compareTo(RuleAppContainer o) { } // SECONDARY key (equal cost only): order deterministically by content so the search does // not - // depend on the (timing-dependent) order in which candidates were generated/selected -- a + // depend on the (timing-dependent) order in which candidates were generated/selected; a // source of run-to-run proof variance under concurrent goal processing. Uses only stable // keys (rule, operator and schema-variable names; structural positions and instantiations); // never object hashCodes or toString(), which can embed identity (e.g. term-label hashes). @@ -73,7 +73,7 @@ public final int compareTo(RuleAppContainer o) { // to explain the overall search order. It only breaks exact cost ties; the bulk of the // order // comes from cost (above), which the tie-break never sees. Cost (aging) and this tie-break - // together keep the multi-worker search deterministic -- the tie-break alone is not the + // together keep the multi-worker search deterministic; the tie-break alone is not the // whole story, so a change that leaves this method intact can still reorder the proof by // shifting costs/ages (e.g. by changing the round in which a candidate is created). return compareByContent(this, o); @@ -89,12 +89,12 @@ private static int compareByContent(RuleAppContainer ca, RuleAppContainer cb) { // surface from the queue in generation order, which follows the sequent/term structure; // ordering ties by position keeps that exploration policy (and thereby proof sizes) close // to the historical one. Rule-name-first regressed large proofs badly (TimSort.binarySort - // doubled): at every tie an alphabetically early rule -- often a split -- beat the + // doubled): at every tie an alphabetically early rule, often a split, beat the // position-order winner, causing splits too early in the search. // // Taclet apps are queued as NoPosTacletApps whose posInOccurrence() is null: their // application position lives in the container, so it is the container position that has - // to be compared -- otherwise two apps of the same taclet at different positions (with + // to be compared; otherwise two apps of the same taclet at different positions (with // equal instantiations) tie, and their order falls back to the history-dependent heap // insertion order. The position also has to be compared before the rule apps are // shortcut-compared by identity: one and the same NoPosTacletApp object is indexed at @@ -122,7 +122,7 @@ private static int compareByContent(RuleAppContainer ca, RuleAppContainer cb) { // Known blind spots, all reached only for two equal-cost apps at the same position (and, // for taclets, with equal instantiation names): compareByName compares operator // names/arity/subterms but NOT bound variables, and a modality's program block is a - // non-subterm child it does not walk -- so two focus terms differing only in bound-variable + // non-subterm child it does not walk, so two focus terms differing only in bound-variable // names or in an embedded program tie (they are then alpha-/program-equivalent for search // purposes). Built-in (non-taclet) apps are ordered here only by rule name and position, so // several apps of the same built-in rule at one position (e.g. multiple @@ -149,7 +149,7 @@ private static PosInOccurrence applicationPosition(RuleAppContainer c) { * from the schema-variable map, so two apps of the same taclet at the same focus that use * different assumes-formulas (e.g. {@code applyEq} instances rewriting with two different * equations) are still tied after {@link #compareInstantiations}; without this comparison the - * queue order of such candidates — and thereby proof search — would depend on the + * queue order of such candidates, and thereby proof search, would depend on the * (history-dependent) order in which they were inserted into the queue. */ private static int compareAssumesInstantiations(TacletApp a, TacletApp b) { @@ -186,7 +186,8 @@ private static int compareAssumesInstantiations(TacletApp a, TacletApp b) { return c; } } - c = compareByName(fa.getSequentFormula().formula(), fb.getSequentFormula().formula()); + c = compareFormulasByName(fa.getSequentFormula().formula(), + fb.getSequentFormula().formula()); if (c != 0) { return c; } @@ -225,7 +226,7 @@ private static int comparePos(PosInOccurrence a, PosInOccurrence b) { if (a.sequentFormula() == b.sequentFormula()) { return 0; } - return compareByName(a.sequentFormula().formula(), b.sequentFormula().formula()); + return compareFormulasByName(a.sequentFormula().formula(), b.sequentFormula().formula()); } private static int compareInstantiations(TacletApp a, TacletApp b) { @@ -235,8 +236,8 @@ private static int compareInstantiations(TacletApp a, TacletApp b) { return 0; } // The maps iterate in build order, which differs between code paths (fresh match, - // re-expansion, assumes completion) even for equal content. Compare canonically -- sizes, - // then the entries sorted by schema-variable name -- so that the result is a consistent + // re-expansion, assumes completion) even for equal content. Compare canonically: sizes, + // then the entries sorted by schema-variable name, so that the result is a consistent // total order: an order-sensitive walk compares mismatched keys and turns compareTo // asymmetric for content-equal apps, which silently corrupts the ordering of the whole // rule-app queue (a leftist heap merges by pairwise comparisons). @@ -282,11 +283,30 @@ private static int compareInstValue(Object va, Object vb) { return String.valueOf(va).compareTo(String.valueOf(vb)); } - /** Structural order on terms by operator names only -- stable across runs (unlike hashCode). */ - private static int compareByName(Term a, Term b) { + /** + * Order on whole sequent formulas: by the cached structural name hash first + * ({@link Term#nameHash()}), then by the structural name walk of + * {@link #compareByName(Term, Term)}. The hash is a pure function of the operator structure + * (so the resulting order is stable across runs, as required for the tie-break) and is cached + * on term instances, making it an O(1) discriminator: only hash collisions ever pay the walk, + * which then keeps the order total and consistent. + */ + static int compareFormulasByName(Term a, Term b) { + if (a == b) { + return 0; + } + final int c = Integer.compare(a.nameHash(), b.nameHash()); + if (c != 0) { + return c; + } + return compareByName(a, b); + } + + /** Structural order on terms by operator names only, stable across runs (unlike hashCode). */ + static int compareByName(Term a, Term b) { // Identical (shared) subterms compare equal without a walk. Terms are structurally shared, // so on large focus/instantiation terms (e.g. deep heap sequents) this skips whole - // subtrees -- the dominant cost of tie-breaking equal-cost rule apps. Order-preserving: + // subtrees, the dominant cost of tie-breaking equal-cost rule apps. Order-preserving: // a == b implies the full comparison would yield 0. if (a == b) { return 0; @@ -330,7 +350,7 @@ public final RuleAppCost getCost() { /** * Add the goal-age term to a strategy-computed cost. Age (the goal time, i.e. number of rules * applied so far) is a single first-class component of every container's cost, contributed here - * rather than inside any {@link de.uka.ilkd.key.strategy.Strategy#computeCost} -- so a strategy + * rather than inside any {@link de.uka.ilkd.key.strategy.Strategy#computeCost}, so a strategy * (and each of its components) computes only its age-free cost, and age is added exactly once * per queued container regardless of how strategies are composed. {@code Top} stays * {@code Top}. diff --git a/key.ncore/src/main/java/org/key_project/logic/Term.java b/key.ncore/src/main/java/org/key_project/logic/Term.java index a7886022e0b..7e2d6641629 100644 --- a/key.ncore/src/main/java/org/key_project/logic/Term.java +++ b/key.ncore/src/main/java/org/key_project/logic/Term.java @@ -46,6 +46,12 @@ public interface Term extends LogicElement, Sorted { /// The set of free quantifiable variables occurring in this term. ImmutableSet freeVars(); + /// A hash folded from the operator names and arities of this term and all its subterms, and + /// nothing else. It ignores term labels and object identity, so unlike [#hashCode()] it is + /// the same in every run. Terms equal up to labels share it; a different value means they + /// differ. + int nameHash(); + /// Returns a serial number for a term. The serial number is not persistent. int serialNumber(); From 7249571a7fbc4289366fa8bc98ddf72402db55af Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 18 Jul 2026 21:34:02 +0200 Subject: [PATCH 05/15] Fix cost-feature locality classifications and add order property tests An anonymous class cannot be annotated, so the locality lookup climbs to the first named class for anonymous ones. Named classes still declare their own locality, because a subclass's overrides may change what the cost depends on. with AI tooling support --- key.core/build.gradle | 5 + .../de/uka/ilkd/key/strategy/CostReuse.java | 8 +- .../ilkd/key/strategy/IntegerStrategy.java | 15 ++ .../AbstractMonomialSmallerThanFeature.java | 26 ++- .../feature/AtomsSmallerThanFeature.java | 14 +- .../feature/MonomialsSmallerThanFeature.java | 10 +- .../DividePolynomialsProjection.java | 1 + .../strategy/termProjection/TermBuffer.java | 10 + .../termgenerator/SuperTermGenerator.java | 4 + .../logic/LexPathOrderingPropertyTest.java | 192 ++++++++++++++++++ .../TieBreakComparatorPropertyTest.java | 125 ++++++++++++ .../strategy/costbased/CostClassifiable.java | 18 +- 12 files changed, 420 insertions(+), 8 deletions(-) create mode 100644 key.core/src/test/java/de/uka/ilkd/key/logic/LexPathOrderingPropertyTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java diff --git a/key.core/build.gradle b/key.core/build.gradle index 3fae6f707e2..f8e5fcaffca 100644 --- a/key.core/build.gradle +++ b/key.core/build.gradle @@ -412,6 +412,11 @@ tasks.register("testRAP", Test) { systemProperty 'key.matcher.compiled', (project.findProperty('matcher.compiled') ?: System.getProperty('key.matcher.compiled', 'false')) + // forward the cost-reuse verification switch to the proof runs in each fork; default off, + // enable with -PcostReuse.verify=true (or -Dkey.strategy.costReuse.verify=true) + systemProperty 'key.strategy.costReuse.verify', + (project.findProperty('costReuse.verify') + ?: System.getProperty('key.strategy.costReuse.verify', 'false')) // (statistics are always written per-process, ..csv; see // ProveTest.getStatisticsFile -- combine the per-fork files after the run.) // set heap size for the test JVM(s) (overridable with -PrapHeap=8g for the large examples) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/CostReuse.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/CostReuse.java index 5e8df723d2a..16ab6178326 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/CostReuse.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/CostReuse.java @@ -58,13 +58,13 @@ * {@link TermGenerator} it holds is at least as local. A generator that walks below the find * ({@code SubtermGenerator}) is find-local; one that walks up to the find's ancestors * ({@code SuperTermGenerator}) is {@link WeakStableCost}; one that reads the whole sequent - * ({@code SequentFormulasGenerator}) is non-local. The walk follows only {@link Feature}- and - * {@link TermGenerator}-typed references, never arbitrary objects: the live feature tree holds - * mutable scratch state (e.g. TermBuffers) that must not be traversed. + * ({@code SequentFormulasGenerator}) is non-local. The walk follows every value that is itself + * cost-classifiable, projections and buffers included, and never arbitrary objects: the live + * feature tree holds mutable scratch state that must not be traversed. * *

* Optional verification (-Dkey.strategy.costReuse.verify): when reuse is applied also - * recompute the cost and log a warning on any mismatch -- a development aid to catch a feature that + * recompute the cost and log a warning on any mismatch, a development aid to catch a feature that * is mis-classified local (it should then get {@link VolatileCost}). */ public final class CostReuse { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 60ac803b4f0..67975a44bb2 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -26,6 +26,7 @@ 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.CostLocality; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; import org.key_project.prover.strategy.costbased.TopRuleAppCost; @@ -671,6 +672,13 @@ public void setContent(Term term, MutableState mState) {} Goal goal, MutableState mState) { return tOne; } + + @Override + public CostLocality locality() { + // a constant term fixed at strategy construction: annotations are looked up on + // the concrete (here: anonymous) class, so the classification is given explicitly + return CostLocality.STABLE; + } }; final JTerm tTwo = getServices().getTermBuilder().zTerm("2"); @@ -688,6 +696,13 @@ public void setContent(Term term, MutableState mState) {} Goal goal, MutableState mState) { return tTwo; } + + @Override + public CostLocality locality() { + // a constant term fixed at strategy construction: annotations are looked up on + // the concrete (here: anonymous) class, so the classification is given explicitly + return CostLocality.STABLE; + } }; bindRuleSet(d, "inEqSimp_or_tautInEqs", diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractMonomialSmallerThanFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractMonomialSmallerThanFeature.java index 437f88d6524..4b691663ede 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractMonomialSmallerThanFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractMonomialSmallerThanFeature.java @@ -32,9 +32,33 @@ protected AbstractMonomialSmallerThanFeature(IntegerLDT numbers) { /** * if {@code op} is a Skolem constant the returned introduction time is the number of taclets - * applied before and including the taclet by which its was introduced. For all other + * applied before and including the taclet by which it was introduced. For all other * operators the returned value is -1 * + *

+ * Although this reads the goal, the value is a constant for every operator a cost evaluation + * can encounter, which is what makes features built on it {@code StableCost}-classifiable: + *

    + *
  1. The compared terms are instantiation terms of the taclet app, so an operator seen here + * either occurs in the goal's sequent or is the app's own fresh {@code SkolemTermSV} + * instantiation.
  2. + *
  3. A sequent operator with a {@code polySimp_newSmallSym} introducer: that application is + * already part of the goal's applied-rule sequence (a symbol cannot occur before the + * application that created it), and its position there never changes; every goal in which the + * symbol occurs lies below the introduction and so agrees on that position. The value is the + * same at every evaluation.
  4. + *
  5. A sequent operator without such an introducer answers {@code -1}, and stays {@code -1}: + * skolem instantiations are always fresh symbols ({@code TacletApp.createSkolemConstant}), so + * no later application can become the introducer of an already existing operator.
  6. + *
  7. An app's own fresh skolem symbol answers {@code -1} for as long as the app exists: its + * introducer would be the app itself, which is unapplied while the app is pending, and once + * applied the app is consumed, so no further evaluation of it takes place.
  8. + *
+ * Case 4 is also the reason the {@code -1} answer must not be cached below: for that symbol + * the answer changes the moment the introducing taclet is applied, and a frozen {@code -1} + * would then leak into evaluations of other apps. + *

+ * * @param op the Operator whose introduction time is queried * @param goal the Goal whose state is queried * @return the introduction time or -1 if not yet introduced or op is not a Skolem constant diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AtomsSmallerThanFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AtomsSmallerThanFeature.java index e4ec1cc7e02..017c34d3874 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AtomsSmallerThanFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AtomsSmallerThanFeature.java @@ -12,13 +12,25 @@ import org.key_project.prover.sequent.PosInOccurrence; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.feature.Feature; +import org.key_project.prover.strategy.costbased.feature.StableCost; import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; /** * Feature that returns zero iff each variable/atom of one monomial is smaller than all variables of - * a second monomial + * a second monomial. + * + *

+ * The value is determined by the compared instantiation terms alone: the atom ordering consists of + * the number-literal distinction, the term-only {@link de.uka.ilkd.key.logic.LexPathOrdering}, and + * the introduction time of basis symbols, which is a constant for every operator a cost evaluation + * can encounter (the argument is given at + * {@link AbstractMonomialSmallerThanFeature#introductionTime}). Hence {@link StableCost} -- the + * same classification, for the same reason, as {@link MonomialsSmallerThanFeature}, which orders + * whole monomials by the same ingredients. + *

*/ +@StableCost public class AtomsSmallerThanFeature extends AbstractMonomialSmallerThanFeature { private final ProjectionToTerm left, right; diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/MonomialsSmallerThanFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/MonomialsSmallerThanFeature.java index 0fde7ece183..15c026541b0 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/MonomialsSmallerThanFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/MonomialsSmallerThanFeature.java @@ -27,7 +27,15 @@ /** * Feature that returns zero iff each monomial of one polynomial is smaller than all monomials of a - * second polynomial + * second polynomial. + * + *

+ * {@link StableCost}: the monomial ordering is determined by the compared instantiation terms alone + * -- multiplication degree, atom counts, the term-only + * {@link de.uka.ilkd.key.logic.LexPathOrdering}, and the introduction time of basis symbols, which + * is a constant for every operator a cost evaluation can encounter (the argument is given at + * {@link AbstractMonomialSmallerThanFeature#introductionTime}). + *

*/ @StableCost public class MonomialsSmallerThanFeature extends AbstractMonomialSmallerThanFeature { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/DividePolynomialsProjection.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/DividePolynomialsProjection.java index c84290ec8be..dedf9654c3e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/DividePolynomialsProjection.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/DividePolynomialsProjection.java @@ -43,6 +43,7 @@ protected Term divide(Monomial numerator, BigInteger denominator, divide(numerator.getCoefficient().negate(), denominator).negate(); return numerator.setCoefficient(newRightCoeff).toTerm(services); } + }; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/TermBuffer.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/TermBuffer.java index 96ccebc8752..d6a7959ee24 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/TermBuffer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/termProjection/TermBuffer.java @@ -5,6 +5,16 @@ import de.uka.ilkd.key.proof.Goal; +import org.key_project.prover.strategy.costbased.feature.StableCost; + +/** + * A buffer holds no state of its own -- it is a key into the per-evaluation + * {@link org.key_project.prover.strategy.costbased.MutableState}, so its value during a cost + * evaluation is whatever the enclosing {@code let} bound in that same evaluation. The locality + * annotation is looked up on the concrete class (the annotations are not {@code @Inherited}), + * so this specialization has to repeat the parent's {@link StableCost}. + */ +@StableCost public class TermBuffer extends org.key_project.prover.strategy.costbased.termProjection.TermBuffer { } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/SuperTermGenerator.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/SuperTermGenerator.java index 7df06bb35c6..501d5a3787f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/SuperTermGenerator.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/SuperTermGenerator.java @@ -49,6 +49,7 @@ protected Iterator createIterator( PosInOccurrence focus, MutableState mState) { return new UpwardsIterator(focus, mState, services); } + }; } @@ -59,6 +60,7 @@ protected Iterator createIterator( PosInOccurrence focus, MutableState mState) { return new UpwardsIterator(focus, mState, services); } + }; } @@ -80,6 +82,8 @@ private boolean generateFurther(Term t, MutableState mState, Services services) return !(cond.compute(t, mState, services) instanceof TopRuleAppCost); } + // same data flow as the enclosing class: ancestors of the focus position + @WeakStableCost abstract static class SuperTermWithIndexGenerator extends SuperTermGenerator { // Both are fixed at construction from the proof's services (one generator is built per // proof and shared by all goals). They used to be lazily filled by generate(), which runs diff --git a/key.core/src/test/java/de/uka/ilkd/key/logic/LexPathOrderingPropertyTest.java b/key.core/src/test/java/de/uka/ilkd/key/logic/LexPathOrderingPropertyTest.java new file mode 100644 index 00000000000..7b5fd045741 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/logic/LexPathOrderingPropertyTest.java @@ -0,0 +1,192 @@ +/* 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.logic; + +import java.util.ArrayList; +import java.util.List; + +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.sort.SortImpl; + +import org.key_project.logic.Name; +import org.key_project.logic.op.Function; +import org.key_project.logic.sort.Sort; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Property test for + * {@link LexPathOrdering#compare(org.key_project.logic.Term, org.key_project.logic.Term)}. + * The ordering is used pairwise to orient rewriting (a rule fires only when its left side is + * strictly greater than its right side), so soundness of the arithmetic normalisation relies on + * the strict part being a strict partial order: irreflexive, antisymmetric and transitive. If + * antisymmetry fails, two terms could each rewrite to the other (a normalisation loop); if + * transitivity fails, the ordering is not well founded. The order is only a partial order -- it + * returns 0 both for equal and for incomparable terms -- so equivalence (compare == 0) is not + * expected to be transitive and is not checked here. + */ +public class LexPathOrderingPropertyTest { + + private static JTerm t(TermFactory tf, Function f, JTerm... subs) { + return tf.createTerm(f, subs); + } + + /** + * Probes the one antisymmetry hazard the curated-signature test above cannot reach: the + * symbol precedence in {@link LexPathOrdering} ties only for equal-name symbols, so a signature + * of distinct-named symbols is a total precedence and never exercises the {@code compareHelp2} + * else-branch that is taken when the operator comparison is a tie and the lexicographic subterm + * comparison is inconclusive. Here we deliberately introduce DISTINCT operator objects that + * SHARE a name (a genuinely partial precedence layer), plus commutation swaps, and assert the + * strict part stays antisymmetric -- a failure would be two terms each orienting below the + * other, i.e. a rewrite loop. + */ + @Test + void sameNamedDistinctOpsDoNotBreakAntisymmetry() { + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final TermFactory tf = services.getTermFactory(); + final Sort s = new SortImpl(new Name("S")); + + // distinct operator objects sharing a name -> a precedence tie for non-identical ops + final Function p1 = new JFunction(new Name("p"), s, s, s); + final Function p2 = new JFunction(new Name("p"), s, s, s); + final Function q1 = new JFunction(new Name("q"), s, s); + final Function q2 = new JFunction(new Name("q"), s, s); + final Function k1 = new JFunction(new Name("k"), s); + final Function k2 = new JFunction(new Name("k"), s); + final Function a = new JFunction(new Name("a"), s); + final Function b = new JFunction(new Name("b"), s); + final Function g = new JFunction(new Name("g"), s, s, s); + + final JTerm ta = t(tf, a), tb = t(tf, b); + final List terms = new ArrayList<>(); + terms.add(t(tf, k1)); // constant named k + terms.add(t(tf, k2)); + for (JTerm x : new JTerm[] { ta, tb }) { + terms.add(t(tf, q1, x)); + terms.add(t(tf, q2, x)); + // commutation swaps under same-named binaries + terms.add(t(tf, p1, x, x)); + terms.add(t(tf, p2, x, x)); + } + terms.add(t(tf, p1, ta, tb)); + terms.add(t(tf, p2, tb, ta)); + terms.add(t(tf, g, t(tf, p1, ta, tb), t(tf, p2, tb, ta))); + terms.add(t(tf, g, t(tf, p2, tb, ta), t(tf, p1, ta, tb))); + terms.add(t(tf, p1, t(tf, q1, ta), t(tf, q2, ta))); + terms.add(t(tf, p1, t(tf, q2, ta), t(tf, q1, ta))); + + final LexPathOrdering ord = new LexPathOrdering(); + final int n = terms.size(); + for (JTerm x : terms) { + assertEquals(0, ord.compare(x, x), "compare(t,t) must be 0 for " + x); + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + final int cij = Integer.signum(ord.compare(terms.get(i), terms.get(j))); + final int cji = Integer.signum(ord.compare(terms.get(j), terms.get(i))); + assertEquals(cij, -cji, "antisymmetry (rewrite-loop) violated for [" + + terms.get(i) + "] vs [" + terms.get(j) + "]"); + } + } + // transitivity of the strict part over the same-named signature + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (ord.compare(terms.get(i), terms.get(j)) >= 0) { + continue; + } + for (int m = 0; m < n; m++) { + if (ord.compare(terms.get(j), terms.get(m)) < 0) { + assertTrue(ord.compare(terms.get(i), terms.get(m)) < 0, + "transitivity violated: " + terms.get(i) + " < " + terms.get(j) + " < " + + terms.get(m)); + } + } + } + } + } + + @Test + void strictPartIsStrictPartialOrder() { + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final TermFactory tf = services.getTermFactory(); + + final Sort s = new SortImpl(new Name("S")); + // constants a, b, c; a unary f; two binaries g, h -- enough operator variety to exercise + // the symbol precedence, the lexicographic subterm comparison and the subterm-dominance + // checks of the LPO. + final Function a = new JFunction(new Name("a"), s); + final Function b = new JFunction(new Name("b"), s); + final Function c = new JFunction(new Name("c"), s); + final Function f = new JFunction(new Name("f"), s, s); + final Function g = new JFunction(new Name("g"), s, s, s); + final Function h = new JFunction(new Name("h"), s, s, s); + + final List base = new ArrayList<>(); + base.add(t(tf, a)); + base.add(t(tf, b)); + base.add(t(tf, c)); + + final List terms = new ArrayList<>(base); + // depth 1 + for (JTerm x : base) { + terms.add(t(tf, f, x)); + } + // depth 2 combinations over the two binaries and the unary + for (JTerm x : base) { + for (JTerm y : base) { + terms.add(t(tf, g, x, y)); + terms.add(t(tf, h, x, y)); + terms.add(t(tf, f, t(tf, f, x))); + } + } + // a few deeper, mixed nestings + for (JTerm x : base) { + terms.add(t(tf, g, t(tf, f, x), x)); + terms.add(t(tf, h, x, t(tf, g, x, x))); + terms.add(t(tf, g, t(tf, g, x, x), t(tf, h, x, x))); + } + + final LexPathOrdering ord = new LexPathOrdering(); + final int n = terms.size(); + + // reflexive tie: compare(t, t) == 0 + for (JTerm x : terms) { + assertEquals(0, ord.compare(x, x), "compare(t,t) must be 0 for " + x); + } + + // antisymmetry: sign(compare(a,b)) == -sign(compare(b,a)) + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + final int cij = Integer.signum(ord.compare(terms.get(i), terms.get(j))); + final int cji = Integer.signum(ord.compare(terms.get(j), terms.get(i))); + assertEquals(cij, -cji, + "antisymmetry violated for [" + terms.get(i) + "] vs [" + terms.get(j) + "]"); + } + } + + // transitivity of the strict part: a= 0) { + continue; + } + for (int k = 0; k < n; k++) { + if (ord.compare(terms.get(j), terms.get(k)) < 0) { + strictTriplesChecked++; + assertTrue(ord.compare(terms.get(i), terms.get(k)) < 0, + "transitivity violated: [" + terms.get(i) + "] < [" + terms.get(j) + + "] < [" + terms.get(k) + "] but not [" + terms.get(i) + "] < [" + + terms.get(k) + "]"); + } + } + } + } + assertTrue(strictTriplesChecked > 0, "no strict chains found, test set too flat"); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java new file mode 100644 index 00000000000..1d1679e3a76 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java @@ -0,0 +1,125 @@ +/* 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.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermFactory; +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.sort.SortImpl; + +import org.key_project.logic.Name; +import org.key_project.logic.Term; +import org.key_project.logic.op.Function; +import org.key_project.logic.sort.Sort; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Property test for {@code RuleAppContainer.compareByName}, the structural term comparison that is + * the content key of the rule-application queue's tie-break. That queue is a leftist heap which + * merges by pairwise comparisons, so the comparator must be a strict weak ordering: irreflexive, + * antisymmetric, and both the strict part and the equivalence (compare == 0) transitive. On terms + * without bound variables, program blocks or labels -- the comparator's documented blind spots -- + * it is meant to be a strict total order, so compare == 0 must coincide with structural equality; + * this test builds exactly such terms and checks all four properties exhaustively. + */ +public class TieBreakComparatorPropertyTest { + + private static Method compareByName; + + private static int cmp(Term a, Term b) { + try { + if (compareByName == null) { + compareByName = RuleAppContainer.class.getDeclaredMethod("compareByName", + Term.class, Term.class); + compareByName.setAccessible(true); + } + return (int) compareByName.invoke(null, a, b); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + private static JTerm t(TermFactory tf, Function f, JTerm... subs) { + return tf.createTerm(f, subs); + } + + @Test + void compareByNameIsStrictTotalOrderOnLabelFreeTerms() { + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final TermFactory tf = services.getTermFactory(); + + final Sort s = new SortImpl(new Name("S")); + final Function a = new JFunction(new Name("a"), s); + final Function b = new JFunction(new Name("b"), s); + final Function c = new JFunction(new Name("c"), s); + final Function f = new JFunction(new Name("f"), s, s); + final Function g = new JFunction(new Name("g"), s, s, s); + final Function h = new JFunction(new Name("h"), s, s, s); + + final List base = new ArrayList<>(); + base.add(t(tf, a)); + base.add(t(tf, b)); + base.add(t(tf, c)); + final List terms = new ArrayList<>(base); + for (JTerm x : base) { + terms.add(t(tf, f, x)); + for (JTerm y : base) { + terms.add(t(tf, g, x, y)); + terms.add(t(tf, h, x, y)); + terms.add(t(tf, f, t(tf, f, x))); + terms.add(t(tf, g, t(tf, f, x), y)); + terms.add(t(tf, h, x, t(tf, g, x, y))); + } + } + final int n = terms.size(); + + // reflexive tie: an element compares equal to itself + for (JTerm x : terms) { + assertEquals(0, cmp(x, x), "compare(t,t) must be 0"); + } + // antisymmetry + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + assertEquals(Integer.signum(cmp(terms.get(i), terms.get(j))), + -Integer.signum(cmp(terms.get(j), terms.get(i))), + "antisymmetry violated for [" + terms.get(i) + "] vs [" + terms.get(j) + "]"); + } + } + // totality on label/binder/program-free terms: compare == 0 only for equal terms + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + final boolean tie = cmp(terms.get(i), terms.get(j)) == 0; + final boolean equal = terms.get(i).equals(terms.get(j)); + assertEquals(equal, tie, "compare==0 must coincide with equality: [" + + terms.get(i) + "] vs [" + terms.get(j) + "]"); + } + } + // transitivity of the strict part + int triples = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (cmp(terms.get(i), terms.get(j)) >= 0) { + continue; + } + for (int k = 0; k < n; k++) { + if (cmp(terms.get(j), terms.get(k)) < 0) { + triples++; + assertTrue(cmp(terms.get(i), terms.get(k)) < 0, + "transitivity violated: " + terms.get(i) + " < " + terms.get(j) + " < " + + terms.get(k)); + } + } + } + } + assertTrue(triples > 0, "test set too flat"); + } +} diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/strategy/costbased/CostClassifiable.java b/key.ncore.calculus/src/main/java/org/key_project/prover/strategy/costbased/CostClassifiable.java index d72df106b99..3711fbe9fb0 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/strategy/costbased/CostClassifiable.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/strategy/costbased/CostClassifiable.java @@ -29,7 +29,17 @@ public interface CostClassifiable { * annotation-driven default is what the vast majority use. */ default CostLocality locality() { - final Class c = getClass(); + Class c = getClass(); + // An anonymous class carries no annotation of its own and cannot be annotated; its + // locality is that of the class it extends, so the lookup climbs to the first named + // class. Named classes do not inherit: a subclass declares its own locality, because + // its overrides may change what the cost depends on. + while (c != null && c.isAnonymousClass() && !hasLocalityAnnotation(c)) { + c = c.getSuperclass(); + } + if (c == null) { + return CostLocality.VOLATILE; + } if (c.isAnnotationPresent(VolatileCost.class)) { return CostLocality.VOLATILE; } @@ -41,4 +51,10 @@ default CostLocality locality() { } return CostLocality.VOLATILE; } + + private static boolean hasLocalityAnnotation(Class c) { + return c.isAnnotationPresent(VolatileCost.class) + || c.isAnnotationPresent(WeakStableCost.class) + || c.isAnnotationPresent(StableCost.class); + } } From db8118e2cff755b775125005b7ee2ca7e9fd8a55 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 18 Jul 2026 21:34:48 +0200 Subject: [PATCH 06/15] Fix Term.depth() and the contains-program marker Two bugfixes in TermImpl. depth() compared each subterm's depth against the cache field, which is -1 while the value is being computed, so every comparison succeeded and the result was the depth of the last subterm plus one instead of the maximum. A regression test pins both argument orders. containsJavaBlockRecursive() answered false for a modality whose program has no statements. The modality is still part of the term and its JavaBlock still carries meta information such as PositionInfos, so such terms must not be treated as program-free (they are excluded from term caching for exactly that reason). The marker now reports every modality; a regression test covers the empty-program case. --- .../java/de/uka/ilkd/key/logic/TermImpl.java | 15 +++++++------ .../java/de/uka/ilkd/key/logic/TestTerm.java | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java index 8cef273f71f..821fd410675 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java +++ b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java @@ -73,10 +73,11 @@ private enum ThreeValuedTruth { private Sort sort; /** - * This flag indicates that the {@link JTerm} itself or one of its children contains a non-empty - * {@link JavaBlock}. {@link JTerm}s which provides a {@link JavaBlock} directly or indirectly - * can't be cached because it is possible that the contained meta information inside the - * {@link JavaBlock}, e.g. {@link PositionInfo}s, are different. + * This flag indicates that the {@link JTerm} itself or one of its children has a modality as + * operator, that is, carries a program. A program with no statements counts as well: the + * modality is still there, and its {@link JavaBlock} still carries meta information such as + * {@link PositionInfo}s. Terms with this flag can't be cached because two of them may differ + * only in that meta information. */ private ThreeValuedTruth containsJavaBlockRecursive = ThreeValuedTruth.UNKNOWN; @@ -243,7 +244,7 @@ public int depth() { int localDepth = -1; for (int i = 0, n = arity(); i < n; i++) { final int subTermDepth = sub(i).depth(); - if (subTermDepth > depth) { + if (subTermDepth > localDepth) { localDepth = subTermDepth; } } @@ -433,7 +434,9 @@ public ImmutableArray getLabels() { public boolean containsJavaBlockRecursive() { if (containsJavaBlockRecursive == ThreeValuedTruth.UNKNOWN) { ThreeValuedTruth result = ThreeValuedTruth.FALSE; - if (!javaBlock().isEmpty()) { + if (op instanceof JModality) { + // a modality with an empty program still counts: the program is part of the + // term, and its JavaBlock still carries position information result = ThreeValuedTruth.TRUE; } else { for (int i = 0, arity = subs.size(); i < arity; i++) { diff --git a/key.core/src/test/java/de/uka/ilkd/key/logic/TestTerm.java b/key.core/src/test/java/de/uka/ilkd/key/logic/TestTerm.java index 885ac180680..2ea9f1843c3 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/logic/TestTerm.java +++ b/key.core/src/test/java/de/uka/ilkd/key/logic/TestTerm.java @@ -77,6 +77,21 @@ private JTerm t4() { return tf.createTerm(p, new JTerm[] { t_pv0 }, null, null); } + @Test + public void testDepth() { + JTerm t_y = tf.createTerm(y); + assertEquals(0, t_y.depth()); + // p(f(y)): a chain of three operators has depth 2 + JTerm deep = tf.createTerm(p, new JTerm[] { t3() }, null, null); + assertEquals(2, deep.depth()); + // p(f(y)) & p(x): the depth of a term is the maximum over all its subterms plus one, + // in particular it is independent of which child the deepest subterm is + JTerm deepFirst = tf.createTerm(Junctor.AND, deep, t1()); + assertEquals(3, deepFirst.depth()); + JTerm deepLast = tf.createTerm(Junctor.AND, t1(), deep); + assertEquals(3, deepLast.depth()); + } + @Test public void testFreeVars1() { JTerm t_allxt2 = tb.all(x, t2()); @@ -232,10 +247,16 @@ public void testIsContainsJavaBlockRecursive() { new ImmutableArray<>(noJB), null, null); JTerm withJBChild = tf.createTerm(Junctor.NOT, withJB); JTerm withJBChildChild = tf.createTerm(Junctor.NOT, withJBChild); + // a modality whose program has no statements still carries a JavaBlock + JTerm withEmptyJB = tf.createTerm( + JModality.getModality(JModality.JavaModalityKind.DIA, + JavaBlock.createJavaBlock(new StatementBlock())), + new ImmutableArray<>(noJB), null, null); assertFalse(noJB.containsJavaBlockRecursive()); assertFalse(noJBWithChild.containsJavaBlockRecursive()); assertTrue(withJB.containsJavaBlockRecursive()); assertTrue(withJBChild.containsJavaBlockRecursive()); assertTrue(withJBChildChild.containsJavaBlockRecursive()); + assertTrue(withEmptyJB.containsJavaBlockRecursive()); } } From 42a42f1456c5c172d7169a82b3bcf78c2c959b18 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 18 Jul 2026 21:35:18 +0200 Subject: [PATCH 07/15] Small performance fixes in strategy and prediction Five independent changes on hot paths of the proof search, none of which changes any proof. OneStepSimplifier spreads its replace-known map over the renaming-invariant term hash instead of a coarser key, so lookups hit fewer collisions. CountOccurrencesFeature counts occurrences with a direct depth-pruned walk of the sequent instead of instantiating the generic term-generator machinery per query. TypeConverter looks up theories by class instead of scanning a list, and PredictCostProver fetches the integer theory once per prediction run instead of per literal. The duplicate-application veto rejects unequal terms by their cached renaming-invariant hash before entering the label-insensitive comparison walks; terms carrying a program are excluded, their hash would walk the whole program. ContainsExecutableCodeTermFeature answers false without walking the term when the cached contains-program marker already says the term is program-free (the query variant keeps walking, queries are function symbols and not covered by the marker). partially with AI tooling support --- .../de/uka/ilkd/key/java/TypeConverter.java | 59 ++++++++---- .../ast/JavaNonTerminalProgramElement.java | 10 ++- .../uka/ilkd/key/rule/OneStepSimplifier.java | 8 +- .../key/strategy/StaticFeatureCollection.java | 11 +-- .../AbstractNonDuplicateAppFeature.java | 24 ++++- .../feature/CountOccurrencesFeature.java | 90 +++++++++++++++++++ .../quantifierHeuristics/HandleArith.java | 20 ++++- .../PredictCostProver.java | 8 +- .../ContainsExecutableCodeTermFeature.java | 8 +- 9 files changed, 199 insertions(+), 39 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/feature/CountOccurrencesFeature.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/java/TypeConverter.java b/key.core/src/main/java/de/uka/ilkd/key/java/TypeConverter.java index 9d6ae38027f..865e3d5be7c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/java/TypeConverter.java +++ b/key.core/src/main/java/de/uka/ilkd/key/java/TypeConverter.java @@ -5,6 +5,7 @@ import java.util.Collection; +import java.util.HashMap; import java.util.Map; import java.util.TreeMap; @@ -44,11 +45,19 @@ public final class TypeConverter { private final TermBuilder tb; private final Services services; - // Maps LDT names to LDT instances. + // Maps LDT names to LDT instances. The map stays sorted by name so that getLDTFor visits + // the theories in a fixed order, independent of the run. private final Map LDTs = new TreeMap<>(); + // The typed accessors below are called at high frequency from the proof-search strategy + // (for example by the arithmetic heuristics for every candidate weighing), so lookups go + // through this class-keyed map: a class hashes by identity, so a lookup costs no name + // comparison. The map is filled generically when the theories are created; adding a new + // theory needs no change in this class. + private final Map, LDT> ldtsByClass = new HashMap<>(); + + /** the heap theory, kept directly because this class itself uses it throughout */ private HeapLDT heapLDT = null; - // private IntegerLDT integerLDT = null; TypeConverter(Services s) { this.services = s; @@ -61,8 +70,22 @@ public void init() { private void init(Map map) { LDTs.putAll(map); - heapLDT = getHeapLDT(); - // integerLDT = getIntegerLDT(); + for (LDT ldt : map.values()) { + ldtsByClass.put(ldt.getClass(), ldt); + } + heapLDT = getLDT(HeapLDT.class); + } + + /** + * The theory of the given class, or {@code null} if no such theory is registered. Theories + * are looked up by their exact class. + * + * @param ldtClass the class of the theory + * @return the theory instance of that class + * @param the type of the theory + */ + public T getLDT(Class ldtClass) { + return ldtClass.cast(ldtsByClass.get(ldtClass)); } @@ -81,55 +104,57 @@ private LDT getLDT(Name ldtName) { } public JavaDLTheory getJavaDLTheory() { - return (JavaDLTheory) getLDT(JavaDLTheory.NAME); + return getLDT(JavaDLTheory.class); } public IntegerLDT getIntegerLDT() { - return (IntegerLDT) getLDT(IntegerLDT.NAME); + return getLDT(IntegerLDT.class); } public FloatLDT getFloatLDT() { - return (FloatLDT) getLDT(FloatLDT.NAME); + return getLDT(FloatLDT.class); } public DoubleLDT getDoubleLDT() { - return (DoubleLDT) getLDT(DoubleLDT.NAME); + return getLDT(DoubleLDT.class); } public RealLDT getRealLDT() { - return (RealLDT) getLDT(RealLDT.NAME); + return getLDT(RealLDT.class); } public BooleanLDT getBooleanLDT() { - return (BooleanLDT) getLDT(BooleanLDT.NAME); + return getLDT(BooleanLDT.class); } public LocSetLDT getLocSetLDT() { - return (LocSetLDT) getLDT(LocSetLDT.NAME); + return getLDT(LocSetLDT.class); } public HeapLDT getHeapLDT() { - return (HeapLDT) getLDT(HeapLDT.NAME); + return heapLDT; } + + public PermissionLDT getPermissionLDT() { - return (PermissionLDT) getLDT(PermissionLDT.NAME); + return getLDT(PermissionLDT.class); } public SeqLDT getSeqLDT() { - return (SeqLDT) getLDT(SeqLDT.NAME); + return getLDT(SeqLDT.class); } public SortLDT getSortLDT() { - return (SortLDT) getLDT(SortLDT.NAME); + return getLDT(SortLDT.class); } public MapLDT getMapLDT() { - return (MapLDT) getLDT(MapLDT.NAME); + return getLDT(MapLDT.class); } public CharListLDT getCharListLDT() { - return (CharListLDT) getLDT(CharListLDT.NAME); + return getLDT(CharListLDT.class); } public Collection getLDTs() { diff --git a/key.core/src/main/java/de/uka/ilkd/key/java/ast/JavaNonTerminalProgramElement.java b/key.core/src/main/java/de/uka/ilkd/key/java/ast/JavaNonTerminalProgramElement.java index c71431025dd..5a2cc53c258 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/java/ast/JavaNonTerminalProgramElement.java +++ b/key.core/src/main/java/de/uka/ilkd/key/java/ast/JavaNonTerminalProgramElement.java @@ -89,10 +89,16 @@ public boolean equals(Object o) { @Override protected int computeHashCode() { - int localHash = 17 * super.computeHashCode(); + // Fold the children with a multiplier that is 3 (mod 8): such a multiplier has maximal + // multiplicative order modulo 2^32, so its powers mix the low bits. The previous 17 is + // 1 (mod 16), so 17^n stayed 1 (mod 16) and barely moved the low bits -- structurally + // repetitive programs then accumulated near-linear low bits and collided into the same hash + // buckets. Equal programs still get equal hashes, so this only redistributes, never breaks. + final int mult = 0x01000193; + int localHash = mult * super.computeHashCode(); for (int i = 0, sz = getChildCount(); i < sz; i++) { final ProgramElement pe = getChildAt(i); - localHash = 17 * localHash + (pe == null ? 0 : pe.hashCode()); + localHash = mult * localHash + (pe == null ? 0 : pe.hashCode()); } return localHash; } 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 c981dc244dd..f996df01c9a 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 @@ -782,8 +782,12 @@ public TermReplacementKey(Term term) { */ @Override public int hashCode() { - return term.op().hashCode(); // Allow more conflicts to ensure that naming and term - // labels are ignored. + // The hash of the equivalence used by equals (equality modulo renaming), cached on + // the term. A well-spread, equals-consistent hash matters here: the replace-known + // context holds one entry per context formula and is probed for every subterm of + // the formula being simplified, so hash collisions turn each probe into a scan of + // all colliding context formulas. + return ((JTerm) term).hashCodeModRenaming(); } /** 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 2581326631f..ff469a87a57 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 @@ -27,8 +27,6 @@ import org.key_project.prover.strategy.costbased.feature.*; import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; import org.key_project.prover.strategy.costbased.termfeature.*; -import org.key_project.prover.strategy.costbased.termgenerator.SequentFormulasGenerator; -import org.key_project.prover.strategy.costbased.termgenerator.SubtermGenerator; import org.key_project.prover.strategy.costbased.termgenerator.TermGenerator; /** @@ -115,14 +113,7 @@ protected static Feature sequentContainsNoPrograms() { } protected static Feature countOccurrences(ProjectionToTerm cutFormula) { - final TermBuffer sf = new TermBuffer(); - final TermBuffer sub = new TermBuffer(); - - return sum(sf, SequentFormulasGenerator.sequent(), - sum(sub, SubtermGenerator.leftTraverse(sf, any()), - // instead of any a condition which stops traversal when - // depth(cutF) > depth(sub) would be better - ifZero(applyTF(cutFormula, eq(sub)), longConst(1), longConst(0)))); + return CountOccurrencesFeature.create(cutFormula); } protected static Feature termSmallerThan(String smaller, String bigger) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractNonDuplicateAppFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractNonDuplicateAppFeature.java index 8bbb084ac72..ae6b3a3e9f1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractNonDuplicateAppFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AbstractNonDuplicateAppFeature.java @@ -99,6 +99,19 @@ private boolean equalInterestingInsts(SVInstantiations inst0, SVInstantiations i return subset(interesting0, interesting1) && subset(interesting1, interesting0); } + /** + * Fast rejection for the label-insensitive comparisons of this class: two terms that are + * equal up to term labels are in particular equal up to renaming of bound variables + * (renaming equality ignores labels), so their cached renaming hash is equal, and a + * differing hash proves inequality without walking the terms. Terms carrying a program are + * left to the full comparison: their renaming hash would walk the whole program, which is + * expensive for terms that live only a few rounds. + */ + private static boolean cannotBeEqualModLabels(JTerm a, JTerm b) { + return !a.containsJavaBlockRecursive() && !b.containsJavaBlockRecursive() + && a.hashCodeModRenaming() != b.hashCodeModRenaming(); + } + /** * Compare two update contexts modulo irrelevant term labels. Labels carry history (e.g. * origin), and a label-sensitive comparison would let a duplicate escape the veto @@ -115,8 +128,12 @@ protected static boolean equalUpdateContext(ImmutableList ctx0, final var it0 = ctx0.iterator(); final var it1 = ctx1.iterator(); while (it0.hasNext()) { - if (!it0.next().update().equalsModProperty(it1.next().update(), - IRRELEVANT_TERM_LABELS_PROPERTY)) { + final JTerm u0 = it0.next().update(); + final JTerm u1 = it1.next().update(); + if (cannotBeEqualModLabels(u0, u1)) { + return false; + } + if (!u0.equalsModProperty(u1, IRRELEVANT_TERM_LABELS_PROPERTY)) { return false; } } @@ -141,7 +158,8 @@ private boolean subset(ImmutableMap> insts final Object inst0 = entry0.value().getInstantiation(); final Object inst1 = instEntry1.getInstantiation(); if (inst0 instanceof JTerm term0 && inst1 instanceof JTerm term1) { - if (!term0.equalsModProperty(term1, IRRELEVANT_TERM_LABELS_PROPERTY)) { + if (cannotBeEqualModLabels(term0, term1) + || !term0.equalsModProperty(term1, IRRELEVANT_TERM_LABELS_PROPERTY)) { return false; } } else if (!inst0.equals(inst1)) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/CountOccurrencesFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/CountOccurrencesFeature.java new file mode 100644 index 00000000000..cb23da472b7 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/CountOccurrencesFeature.java @@ -0,0 +1,90 @@ +/* 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.feature; + +import de.uka.ilkd.key.logic.JTerm; + +import org.key_project.logic.Term; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.sequent.SequentFormula; +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.Feature; +import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; + +import org.jspecify.annotations.NonNull; + +import static de.uka.ilkd.key.logic.equality.RenamingTermProperty.RENAMING_TERM_PROPERTY; + +/** + * Counts how often a given term occurs in the sequent: the returned cost is the number of + * positions, over all formulas of the goal's sequent and all their subterms, whose term is equal + * to the given term up to renaming of bound variables. Used by the splitting heuristics to + * prefer cutting over formulas that occur often. + * + *

+ * The count is computed directly instead of with a comprehension over all subterms + * ({@code sum(sf, sequent, sum(sub, subterms(sf), ...))}): two terms that are equal up to + * renaming have the same depth, so subterms whose depth differs from the target's cannot be + * occurrences, and subterms shallower than the target cannot contain one either. The walk + * therefore only descends while a node is deeper than the target and only compares nodes of + * exactly the target's depth. On large sequents this skips almost the whole traversal; the + * counted result is the same. ({@link Term#depth()} is cached on the term, so the guard costs a + * field read.) + * + *

+ * If the projection has no value (its schema variable is not instantiated), the result is + * {@link TopRuleAppCost}, as with the comprehension it replaces. + */ +public class CountOccurrencesFeature> implements Feature { + + private final ProjectionToTerm target; + + private CountOccurrencesFeature(ProjectionToTerm target) { + this.target = target; + } + + public static > Feature create( + ProjectionToTerm target) { + return new CountOccurrencesFeature<>(target); + } + + @SuppressWarnings("unchecked") + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, G goal, MutableState mState) { + final Term targetTerm = target.toTerm(app, pos, (Goal) goal, mState); + if (targetTerm == null) { + assert false : "CountOccurrencesFeature: got undefined argument (null)"; + return TopRuleAppCost.INSTANCE; + } + final int targetDepth = targetTerm.depth(); + long count = 0; + for (final SequentFormula sf : goal.sequent()) { + count += occurrences(sf.formula(), (JTerm) targetTerm, targetDepth); + } + return NumberRuleAppCost.create(count); + } + + private static long occurrences(Term t, JTerm target, int targetDepth) { + final int depth = t.depth(); + if (depth < targetDepth) { + // t and all its subterms are too shallow to be an occurrence + return 0; + } + if (depth == targetDepth) { + // subterms of t are shallower than the target, so only t itself can match + return RENAMING_TERM_PROPERTY.equalsModThisProperty(t, target) ? 1 : 0; + } + long count = 0; + for (int i = 0, n = t.arity(); i < n; i++) { + count += occurrences(t.sub(i), target, targetDepth); + } + return count; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java index 5316c41be9c..d5cf4ad4bdc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java @@ -53,7 +53,14 @@ private static boolean isArithComparison(JTerm t, IntegerLDT ig) { * problem if it cann't be proved. */ public static JTerm provedByArith(JTerm problem, Services services) { - final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); + return provedByArith(problem, services.getTypeConverter().getIntegerLDT(), services); + } + + /** + * The variant of {@link #provedByArith(JTerm, Services)} taking the integer theory, which + * one decision consults several times. + */ + static JTerm provedByArith(JTerm problem, IntegerLDT integerLDT, Services services) { if (!isArithComparison(problem, integerLDT) && strippedOp(problem) != Equality.EQUALS) { // neither an (in)equality nor an equality: formatArithTerm yields false and // provedArithEqual returns the problem unchanged -- bail before locking the cache. @@ -147,7 +154,16 @@ private static JTerm provedArithEqual(JTerm problem, TermBuilder tb, Services se * @return trueT if true, falseT if false, and atom if can't be prove; */ public static JTerm provedByArith(JTerm problem, JTerm axiom, Services services) { - final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); + return provedByArith(problem, axiom, services.getTypeConverter().getIntegerLDT(), + services); + } + + /** + * The variant of {@link #provedByArith(JTerm, JTerm, Services)} taking the integer theory, + * which one decision consults several times. + */ + static JTerm provedByArith(JTerm problem, JTerm axiom, IntegerLDT integerLDT, + Services services) { if (!isArithComparison(problem, integerLDT) || !isArithComparison(axiom, integerLDT)) { // not an arithmetic implication: formatArithTerm would yield false for one side and // this method returns the unproved problem -- bail before allocating the key and diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java index 1b758def9fd..11ed848decb 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java @@ -38,9 +38,13 @@ public class PredictCostProver { private final Services services; + /** the integer theory, fetched once because a prediction judges many literals in a row */ + private final de.uka.ilkd.key.ldt.IntegerLDT integerLDT; + private PredictCostProver(JTerm instance, ImmutableSet assertList, Services services) { this.assertLiterals = assertList; this.services = services; + this.integerLDT = services.getTypeConverter().getIntegerLDT(); this.tb = services.getTermBuilder(); this.trueT = tb.tt(); this.falseT = tb.ff(); @@ -108,7 +112,7 @@ private JTerm provedBySelf(JTerm problem) { return negated ? falseT : trueT; } } - JTerm arithRes = HandleArith.provedByArith(pro, services); + JTerm arithRes = HandleArith.provedByArith(pro, integerLDT, services); if (TriggerUtils.isTrueOrFalse(arithRes)) { return negated ? tb.not(arithRes) : arithRes; } else { @@ -151,7 +155,7 @@ private JTerm provedByAnother(JTerm problem, JTerm axiom) { if (TriggerUtils.isTrueOrFalse(res)) { return res; } - return HandleArith.provedByArith(problem, axiom, services); + return HandleArith.provedByArith(problem, axiom, integerLDT, services); } // (5) combine rules diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/termfeature/ContainsExecutableCodeTermFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/termfeature/ContainsExecutableCodeTermFeature.java index 1461954e789..347bb87b22e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/termfeature/ContainsExecutableCodeTermFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/termfeature/ContainsExecutableCodeTermFeature.java @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy.termfeature; +import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.op.IProgramMethod; import de.uka.ilkd.key.logic.op.Quantifier; @@ -38,7 +39,12 @@ private boolean containsExec(Term t, MutableState mState, LogicServices services if (t.isRigid()) { return false; } - // if ( t.isContainsJavaBlockRecursive() ) return true; + // a term without any modality cannot contain a program; the flag is cached on the + // term, so this prunes the whole walk for program-free formulas (queries are function + // symbols and not covered by the flag, so the query variant must keep walking) + if (!considerQueries && !((JTerm) t).containsJavaBlockRecursive()) { + return false; + } final var op = t.op(); switch (op) { From cefc6c99f65187c89ee7690d1c7c5ce023fe67f7 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sat, 18 Jul 2026 21:36:12 +0200 Subject: [PATCH 08/15] Widen the cached term and position hashes and pack the term markers One is only termporart. But all of them have been proven to improve performance significantly (not just by a few percent) with AI tooling support --- .../java/de/uka/ilkd/key/logic/TermImpl.java | 150 ++++++++++++------ .../prover/sequent/PosInOccurrence.java | 11 +- .../java/org/key_project/logic/PosInTerm.java | 18 ++- 3 files changed, 119 insertions(+), 60 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java index 821fd410675..7dc1afa095b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java +++ b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java @@ -55,15 +55,35 @@ class TermImpl implements JTerm { private final ImmutableArray boundVars; // caches - private enum ThreeValuedTruth { - TRUE, FALSE, UNKNOWN - } - private int depth = -1; /** - * A cached value for computing the term's rigidness. + * The three-valued cached markers of this term, packed two bits each into one int: + * {@code 00} = not yet computed, {@code 01} = false, {@code 10} = true. The markers are + *

    + *
  • rigidness ({@link #isRigid()}); + *
  • whether the term or one of its children has a modality as operator, that is, carries a + * program ({@link #containsJavaBlockRecursive()}). A program with no statements counts as + * well: the modality is still there, and its {@link JavaBlock} still carries meta information + * such as {@link PositionInfo}s. Terms with this marker can't be cached because two of them + * may differ only in that meta information; + *
  • whether the term or one of its children has a {@link Transformer} operator + * ({@link #containsTransformerRecursive()}). + *
+ * One int instead of three fields keeps the term object small. Writes of an int are atomic; + * two threads caching different markers at once can lose one of the two updates, which only + * means that marker is recomputed on its next query (every marker is a pure function of the + * term, so any computed value is the correct one). */ - private ThreeValuedTruth rigid = ThreeValuedTruth.UNKNOWN; + private int flags; + + private static final int FLAGS_RIGID_SHIFT = 0; + private static final int FLAGS_JAVABLOCK_SHIFT = 2; + private static final int FLAGS_TRANSFORMER_SHIFT = 4; + private static final int FLAG_MASK = 3; + private static final int FLAG_FALSE = 1; + private static final int FLAG_TRUE = 2; + + private int depth = -1; private ImmutableSet freeVars = null; /** * Cached {@link #hashCode()} value. @@ -72,28 +92,17 @@ private enum ThreeValuedTruth { private Sort sort; - /** - * This flag indicates that the {@link JTerm} itself or one of its children has a modality as - * operator, that is, carries a program. A program with no statements counts as well: the - * modality is still there, and its {@link JavaBlock} still carries meta information such as - * {@link PositionInfo}s. Terms with this flag can't be cached because two of them may differ - * only in that meta information. - */ - private ThreeValuedTruth containsJavaBlockRecursive = ThreeValuedTruth.UNKNOWN; - - /** caches whether this term or a (direct/indirect) child has a {@link Transformer} operator. */ - private ThreeValuedTruth containsTransformerRecursive = ThreeValuedTruth.UNKNOWN; - /** * Cached renaming-invariant hashCode ({@link RenamingTermProperty#hashCodeModThisProperty}), - * used to fast-reject unequal pairs in equality modulo renaming. {@code 0} = not yet computed. + * used to fast-reject unequal pairs in equality modulo renaming. {@code -1} = not yet + * computed. */ - private int hashcodeModRenaming = 0; + private int hashcodeModRenaming = -1; /** - * Cached {@link #nameHash()} value. {@code 0} = not yet computed. + * Cached {@link #nameHash()} value. {@code -1} = not yet computed. */ - private int nameHash = 0; + private int nameHash = -1; // ------------------------------------------------------------------------- // constructors @@ -223,19 +232,44 @@ public Sort sort() { @Override public int nameHash() { - if (nameHash == 0) { + if (nameHash == -1) { + computeHashes(); + } + return nameHash; + } + + /** + * Fills the caches of {@link #hashCode()} and {@link #nameHash()} together. Both hashes are + * recursions over the whole subterm tree, so a term that needs both would walk the tree + * twice; this walk visits every subterm once and fills both caches while the term is in the + * processor cache. The values are exactly those of the two separate computations: the + * hashCode part is still produced by the (subclass-overridable) {@link #computeHashCode()}, + * which finds all subterm hashes already cached. + */ + private void computeHashes() { + // Iterate the subterm array, not arity(): the term factory probes hashCode() before it + // validates that the operator's arity matches the subterm count, so the two can differ. + final int n = subs.size(); + for (int i = 0; i < n; i++) { + if (subs.get(i) instanceof TermImpl t && (t.hashcode == -1 || t.nameHash == -1)) { + t.computeHashes(); + } + } + if (hashcode == -1) { + this.hashcode = computeHashCode(); + } + if (nameHash == -1) { int h = 5; h = h * 31 + op.name().toString().hashCode(); h = h * 31 + arity(); - for (int i = 0, n = arity(); i < n; i++) { - h = h * 31 + sub(i).nameHash(); + for (int i = 0; i < n; i++) { + h = h * 31 + subs.get(i).nameHash(); } - if (h == 0) { - h = 1; + if (h == -1) { + h = 0; } nameHash = h; } - return nameHash; } @Override @@ -255,24 +289,37 @@ public int depth() { } + /** Reads the two-bit marker at {@code shift}: 0 = not yet computed, else FLAG_FALSE/TRUE. */ + private int flag(int shift) { + return (flags >> shift) & FLAG_MASK; + } + + /** Caches the two-bit marker at {@code shift}. */ + private void setFlag(int shift, boolean value) { + flags |= (value ? FLAG_TRUE : FLAG_FALSE) << shift; + } + @Override public boolean isRigid() { - if (rigid == ThreeValuedTruth.UNKNOWN) { + int rigid = flag(FLAGS_RIGID_SHIFT); + if (rigid == 0) { + boolean localIsRigid; if (!op.isRigid()) { - rigid = ThreeValuedTruth.FALSE; + localIsRigid = false; } else { - ThreeValuedTruth localIsRigid = ThreeValuedTruth.TRUE; + localIsRigid = true; for (int i = 0, n = arity(); i < n; i++) { if (!sub(i).isRigid()) { - localIsRigid = ThreeValuedTruth.FALSE; + localIsRigid = false; break; } } - rigid = localIsRigid; } + setFlag(FLAGS_RIGID_SHIFT, localIsRigid); + return localIsRigid; } - return rigid == ThreeValuedTruth.TRUE; + return rigid == FLAG_TRUE; } @@ -333,8 +380,7 @@ public boolean equals(Object o) { @Override public final int hashCode() { if (hashcode == -1) { - // compute into local variable first to be thread-safe. - this.hashcode = computeHashCode(); + computeHashes(); } return hashcode; } @@ -432,23 +478,25 @@ public ImmutableArray getLabels() { */ @Override public boolean containsJavaBlockRecursive() { - if (containsJavaBlockRecursive == ThreeValuedTruth.UNKNOWN) { - ThreeValuedTruth result = ThreeValuedTruth.FALSE; + int marker = flag(FLAGS_JAVABLOCK_SHIFT); + if (marker == 0) { + boolean result = false; if (op instanceof JModality) { // a modality with an empty program still counts: the program is part of the // term, and its JavaBlock still carries position information - result = ThreeValuedTruth.TRUE; + result = true; } else { for (int i = 0, arity = subs.size(); i < arity; i++) { if (subs.get(i).containsJavaBlockRecursive()) { - result = ThreeValuedTruth.TRUE; + result = true; break; } } } - this.containsJavaBlockRecursive = result; + setFlag(FLAGS_JAVABLOCK_SHIFT, result); + return result; } - return containsJavaBlockRecursive == ThreeValuedTruth.TRUE; + return marker == FLAG_TRUE; } /** @@ -456,31 +504,33 @@ public boolean containsJavaBlockRecursive() { * {@link RenamingTermProperty} to fast-reject pairs that cannot be equal modulo renaming. */ public int hashCodeModRenaming() { - if (hashcodeModRenaming == 0) { + if (hashcodeModRenaming == -1) { final int h = de.uka.ilkd.key.logic.equality.RenamingTermProperty.RENAMING_TERM_PROPERTY .hashCodeModThisProperty(this); - hashcodeModRenaming = h == 0 ? 1 : h; + hashcodeModRenaming = h == -1 ? 0 : h; } return hashcodeModRenaming; } @Override public boolean containsTransformerRecursive() { - if (containsTransformerRecursive == ThreeValuedTruth.UNKNOWN) { - ThreeValuedTruth result = ThreeValuedTruth.FALSE; + int marker = flag(FLAGS_TRANSFORMER_SHIFT); + if (marker == 0) { + boolean result = false; if (op instanceof Transformer) { - result = ThreeValuedTruth.TRUE; + result = true; } else { for (int i = 0, arity = subs.size(); i < arity; i++) { if (subs.get(i).containsTransformerRecursive()) { - result = ThreeValuedTruth.TRUE; + result = true; break; } } } - this.containsTransformerRecursive = result; + setFlag(FLAGS_TRANSFORMER_SHIFT, result); + return result; } - return containsTransformerRecursive == ThreeValuedTruth.TRUE; + return marker == FLAG_TRUE; } diff --git a/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/PosInOccurrence.java b/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/PosInOccurrence.java index 44fadc9a2c0..934f8cc9543 100644 --- a/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/PosInOccurrence.java +++ b/key.ncore.calculus/src/main/java/org/key_project/prover/sequent/PosInOccurrence.java @@ -31,8 +31,11 @@ public static PosInOccurrence findInSequent(Sequent seq, int formulaNumber, PosI } /// compute hash lazily: instances of [PosInOccurrence] are often created by descending a term - /// computing it eagerly in the constructor is wasted effort for unused instances - private short hashCode; + /// computing it eagerly in the constructor is wasted effort for unused instances. + /// Full 32 bit wide: a 16-bit hash has only 65536 values, far fewer than the positions + /// occurring in a large sequent, so position-keyed hash maps degenerated into collision + /// chains. The wider field costs no memory, the object's alignment padding absorbs it. + private int hashCode; /// the constrained formula the pos in occurrence describes private final SequentFormula sequentFormula; @@ -206,9 +209,9 @@ private boolean equalsHelp(final PosInOccurrence cmp) { @Override public int hashCode() { - short h = hashCode; + int h = hashCode; if (h == 0) { - h = (short) (sequentFormula.hashCode() * 13 + posInTerm.hashCode()); + h = sequentFormula.hashCode() * 13 + posInTerm.hashCode(); if (h == 0) { h = 1; } diff --git a/key.ncore/src/main/java/org/key_project/logic/PosInTerm.java b/key.ncore/src/main/java/org/key_project/logic/PosInTerm.java index 326e1697c63..95f8495eea2 100644 --- a/key.ncore/src/main/java/org/key_project/logic/PosInTerm.java +++ b/key.ncore/src/main/java/org/key_project/logic/PosInTerm.java @@ -11,10 +11,16 @@ public class PosInTerm { private static final PosInTerm TOP_LEVEL = new PosInTerm(); - // to save memory, we use 16bit integers (unsigned) instead of 32bit + // to save memory, the path entries use 16bit integers (unsigned) instead of 32bit private final char[] positions; private final char size; - private volatile char hash = (char) -1; + /** + * Cached hash, full 32 bit wide. A 16-bit hash (as the path entries use) has only 65536 + * values, far fewer than the positions occurring in one large formula, so position-keyed + * hash maps degenerated into collision chains (treeified buckets, equals-heavy lookups). + * The wider field costs no memory: the object's 8-byte alignment padding absorbs it. + */ + private volatile int hash = -1; private volatile boolean copy; public PosInTerm(int[] path) { @@ -225,12 +231,12 @@ public Term getSubTerm(Term t) { } public int hashCode() { - if (hash == (char) -1) { - char localHash = 13; + if (hash == -1) { + int localHash = 13; for (int i = 0; i < size; i++) { - localHash = (char) (13 * localHash + positions[i]); + localHash = 13 * localHash + positions[i]; } - localHash = (localHash == (char) -1) ? 0 : localHash; + localHash = (localHash == -1) ? 0 : localHash; hash = localHash; } return hash; From 63ea2b5b1c25cd0ed11cc86b43315f707edd0827 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sun, 19 Jul 2026 18:02:54 +0200 Subject: [PATCH 09/15] Improve quantifier trigger heuristics Makes triggers theory aware and improves the quality of the produced instantiation candidates by rejecting unhelpful ones and improving precision on detecting helpful instantiations. It also assigns cost tiers to found candidates to distinguish candidates more likely to help from others. The congruence orientation, the polarity walk and the minimal-cover search are pinned by unit tests. with AI tooling support --- .../de/uka/ilkd/key/java/ServiceCaches.java | 15 + .../uka/ilkd/key/rule/OneStepSimplifier.java | 6 +- .../quantifierHeuristics/Congruence.java | 179 ++++++++++ .../EqualityConstraint.java | 10 +- .../EqualityTheorySupport.java | 103 ++++++ .../quantifierHeuristics/GenPolTieBreak.java | 149 ++++++++ .../quantifierHeuristics/HandleArith.java | 39 ++- .../HeapArrayTheorySupport.java | 160 +++++++++ .../quantifierHeuristics/Instantiation.java | 47 +++ .../IntegerTheorySupport.java | 122 +++++++ .../quantifierHeuristics/MultiTrigger.java | 5 + .../PolarityOccurrenceTieBreak.java | 331 ++++++++++++++++++ .../PolarityTieBreak.java | 23 ++ .../PredictCostProver.java | 328 +++++++++-------- .../QuantifierInstantiationTieBreak.java | 63 ++++ .../QuantifierTheorySupport.java | 131 +++++++ .../quantifierHeuristics/TriggersSet.java | 222 ++++++++---- .../TwoSidedMatching.java | 12 +- .../quantifierHeuristics/UniTrigger.java | 21 +- .../TriggeredInstantiations.java | 13 +- .../quantifierHeuristics/CongruenceTest.java | 122 +++++++ .../quantifierHeuristics/HandleArithTest.java | 97 +++++ .../PolarityWalkTest.java | 129 +++++++ .../PredictCostProverTest.java | 117 +++++++ .../quantifierHeuristics/TestTriggersSet.java | 56 +++ 25 files changed, 2250 insertions(+), 250 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Congruence.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityTheorySupport.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/GenPolTieBreak.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeapArrayTheorySupport.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/IntegerTheorySupport.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityOccurrenceTieBreak.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityTieBreak.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierInstantiationTieBreak.java create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierTheorySupport.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/CongruenceTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArithTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityWalkTest.java create mode 100644 key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProverTest.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java b/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java index 81f710f154d..26b11049d5c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java +++ b/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java @@ -140,6 +140,17 @@ public class ServiceCaches implements SessionCaches { private final Map triggerSetCache = new ConcurrentLruCache<>(1000); + /** + * Per-formula operator-occurrence summary for the quantifier instantiation tie-break (which + * operators occur in a sequent formula, and which at proving polarity). A sequent step + * replaces few formulas, and the {@link org.key_project.prover.sequent.SequentFormula} objects + * are immutable and shared across the sequents of a branch, so the summary is memoised per + * formula rather than recomputed per sequent. The value is opaque here (an + * {@code Instantiation.OccInfo}) to keep this package independent of the strategy package. + */ + private final Map formulaOccurrenceCache = + new ConcurrentLruCache<>(10000); + /** * Map from Term(allTerm) to ClausesGraph */ @@ -239,6 +250,10 @@ public final Map getMonomialCache() { return monomialCache; } + public final Map getFormulaOccurrenceCache() { + return formulaOccurrenceCache; + } + public final Map getPolynomialCache() { return polynomialCache; } 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 f996df01c9a..aef7e5c94a6 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 @@ -79,11 +79,13 @@ 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 = ImmutableList.nil() - .append("concrete").append("simplify_select_elim_store").append("concrete_java").append("update_elim") + .append("concrete").append("simplify_select_elim_store").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, false, false, true, true, true, false }; + private static final boolean[] bottomUp = + { false, false, false, false, true, true, true, false }; // OSS is shared per proof and runs concurrently on every parallel-prover worker. Its two caches // are PURE (the value is a function of the key: "does this formula simplify?" / "this term is // irreducible"), so eviction order is irrelevant to the result and a striped (lower-contention) diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Congruence.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Congruence.java new file mode 100644 index 00000000000..13dd3245928 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Congruence.java @@ -0,0 +1,179 @@ +/* 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.quantifierHeuristics; + +import java.util.HashMap; +import java.util.Map; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermFactory; +import de.uka.ilkd.key.logic.op.Equality; + +import org.key_project.util.collection.ImmutableSet; + +/** + * Equality reasoning over the ground equalities assumed on a sequent, used by the quantifier + * instantiation cost prediction. The two sides of every assumed equality are merged into a class, + * and a term is rewritten to the representatives of its subterms, so that a clause literal already + * satisfied by those equalities becomes syntactically equal to an assumed literal. The instance + * then predicts as non-contributing and is not proposed as a useful step. + * + * Each merge is oriented the way the equality is written on the sequent: occurrences of the left + * side rewrite to the right side. The proof search normalises sequent equalities by the rules of + * the owning theory, so this direction is the theory-established one. A + * {@link QuantifierTheorySupport} can veto a rewrite that would disturb the normal forms its + * decisions depend on ({@link QuantifierTheorySupport#allowsEqualityRewrite}); then the opposite + * direction is tried, and a doubly vetoed equality is left out of the congruence. + * + * One congruence is built per sequent in {@link Instantiation} and shared across the cost + * predictions of all candidate instantiations of the quantified formula, so the union-find is + * built once rather than once per candidate. + */ +final class Congruence { + + /** Union-find parent map over the terms merged by the assumed equalities. */ + private final Map parent = new HashMap<>(); + + /** The (cached) factory used to rebuild normalised terms. */ + private final TermFactory tf; + + /** Access to the theory operators, passed to the theory supports on each veto check. */ + private final Services services; + + /** + * @param assumedLiterals the literals assumed true on the sequent + * @param services access to the term factory and the theory operators + */ + Congruence(ImmutableSet assumedLiterals, Services services) { + this.services = services; + this.tf = services.getTermFactory(); + for (final JTerm lit : assumedLiterals) { + if (lit.op() == Equality.EQUALS) { + union(lit.sub(0), lit.sub(1)); + } + } + } + + /** Results of {@link #normalize}; this object is per sequent and thread-confined. */ + private final Map normalized = new HashMap<>(); + + /** Whether the sequent asserts no equality; then {@link #normalize} is the identity. */ + boolean isTrivial() { + return parent.isEmpty(); + } + + /** The representative of {@code t}'s class, or {@code t} itself if it is in no class. */ + private JTerm find(JTerm t) { + // Iterative with a second compression pass: the merge direction is dictated by the + // sequent, so ranks cannot bound the chains, and a recursive walk would grow the stack + // with the chain length. + JTerm root = t; + JTerm p; + while ((p = parent.get(root)) != null) { + root = p; + } + JTerm walk = t; + while ((p = parent.get(walk)) != null && p != root) { + parent.put(walk, root); + walk = p; + } + return root; + } + + /** + * Merges the classes of the two sides of an assumed equality {@code a = b}, preferring the + * sequent's own orientation: the representative of {@code a}'s class points to the + * representative of {@code b}'s class, so occurrences of the left side rewrite to the right + * side. A direction that is ill sorted or vetoed by a theory support is not installed; then + * the flipped direction is tried, and if that is rejected too the equality does not take part + * in the congruence. + */ + private void union(JTerm a, JTerm b) { + final JTerm ra = find(a); + final JTerm rb = find(b); + if (ra.equals(rb)) { + return; + } + if (allowed(ra, rb)) { + parent.put(ra, rb); + } else if (allowed(rb, ra)) { + parent.put(rb, ra); + } + } + + /** + * Whether occurrences of {@code from} may be rewritten to {@code to}. + * + * The representative's sort must equal or specialise the rewritten side's sort: every operator + * position accepting a term of {@code from}'s sort then accepts the representative, so the + * rebuild in {@link #normalize} stays well sorted. A widening direction is ill sorted: a + * contract equality {@code cast<[int[]]>(dest) = dest} read left to right would put the + * {@code Object}-sorted variable into positions requiring {@code int[]}. The sort condition + * holds transitively along the parent links, since every link narrows the sort. On top of the + * sort condition every theory support must permit the rewrite. + * + * @param from the class representative that would point to {@code to} + * @param to the term that would become the representative of the merged class + * @return whether the rewrite is well sorted and no theory support vetoes it + */ + private boolean allowed(JTerm from, JTerm to) { + if (to.sort() != from.sort() && !to.sort().extendsTrans(from.sort())) { + return false; + } + for (final QuantifierTheorySupport support : TriggersSet.THEORY_SUPPORTS) { + if (!support.allowsEqualityRewrite(from, to, services)) { + return false; + } + } + return true; + } + + /** + * Rewrites {@code t} bottom-up, replacing each subterm by its class representative. Quantified + * subterms are left untouched. + * + * @param t a term to normalise + * @return the congruence-normal form of {@code t} + */ + JTerm normalize(JTerm t) { + if (parent.isEmpty() || !t.boundVars().isEmpty()) { + return t; + } + // Shared subterms are re-normalized once per occurrence otherwise, and the literals of + // one congruence are normalized again for every candidate instance sharing it. + final JTerm memo = normalized.get(t); + if (memo != null) { + return memo; + } + final JTerm result = normalizeUncached(t); + normalized.put(t, result); + return result; + } + + private JTerm normalizeUncached(JTerm t) { + if (t.arity() == 0) { + return find(t); + } + final JTerm[] subs = new JTerm[t.arity()]; + boolean changed = false; + for (int i = 0; i < t.arity(); i++) { + subs[i] = normalize(t.sub(i)); + if (subs[i] != t.sub(i)) { + changed = true; + } + } + if (!changed) { + return find(t); + } + try { + return find(tf.createTerm(t.op(), subs)); + } catch (org.key_project.logic.TermCreationException e) { + // the orientation keeps rewrites sort-compatible, but an operator with a stricter + // requirement can still reject the rebuilt term; this is only a heuristic, so give + // the term up unnormalised rather than fail the proof search + return t; + } + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityConstraint.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityConstraint.java index f308ce65fb3..9ad4e6611da 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityConstraint.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityConstraint.java @@ -557,9 +557,13 @@ private Constraint normalize(Metavariable mv, JTerm t, boolean modifyThis, // MV cycles are impossible if the orders of MV pairs are // correct - if (!t.isRigid()) { - return TOP; - } + // A metavariable may be bound to a ground non-rigid term. This is only trigger + // matching: the metavariable stands for a quantifier instance, and instantiating a + // quantifier with a non-rigid term (a program value like a pivot index, or a heap) is + // sound, the wary substitution at taclet application takes care of modalities. Array + // indices such as a split result are non-rigid, and rejecting them here would strand + // the instantiation the proof needs. The binding is dropped anyway if it is a + // metavariable or contains free variables (below). // metavariable instantiations must not contain free variables if (!t.freeVars().isEmpty() || diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityTheorySupport.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityTheorySupport.java new file mode 100644 index 00000000000..3442c475a1e --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/EqualityTheorySupport.java @@ -0,0 +1,103 @@ +/* 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.quantifierHeuristics; + +import java.util.List; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.op.Equality; +import de.uka.ilkd.key.logic.op.Junctor; + +import org.key_project.logic.op.Operator; +import org.key_project.logic.op.QuantifiableVariable; +import org.key_project.util.collection.ImmutableSet; + +import static de.uka.ilkd.key.logic.equality.RenamingTermProperty.RENAMING_TERM_PROPERTY; + +/** + * Support for the equality theory. + * + * Rejects the equality {@code =} as a trigger (matching on it has not been observed to help + * instantiation) and provides no derived triggers. For cost prediction it decides a literal that is + * an equality or equivalence whose two sides are equal up to renaming, and decides an arbitrary + * literal that equals an assumed one up to renaming (or contradicts it under a negation). + */ +final class EqualityTheorySupport implements QuantifierTheorySupport { + + /** + * Rejects the equality {@code =} as a trigger. + * + * @param candidate a trigger candidate that contains the quantified variables + * @param services access to the theory operators + * @return whether the candidate is rejected + */ + @Override + public boolean rejectsAsTrigger(JTerm candidate, Services services) { + return candidate.op() == Equality.EQUALS; + } + + /** + * Provides no derived triggers. + * + * @param term an accepted trigger term + * @param clauseVariables the quantified variables of the clause the trigger belongs to + * @param services access to the theory operators + * @return the empty list + */ + @Override + public List provideTriggers(JTerm term, + ImmutableSet clauseVariables, Services services) { + return List.of(); + } + + /** + * Checks whether the literal is an equality or equivalence whose two sides are equal up to + * renaming. + * + * @param strippedLiteral a literal without leading negations + * @param services access to the theory operators + * @return {@code PROVED} if the two sides are equal up to renaming, otherwise {@code UNKNOWN} + */ + @Override + public LiteralDecision decideStrippedSelf(JTerm strippedLiteral, Services services) { + final Operator op = strippedLiteral.op(); + if (op == Equality.EQUALS || op == Equality.EQV) { + if (RENAMING_TERM_PROPERTY.equalsModThisProperty(strippedLiteral.sub(0), + strippedLiteral.sub(1))) { + return LiteralDecision.PROVED; + } + } + return LiteralDecision.UNKNOWN; + } + + /** + * Checks whether the literal follows from the axiom by equality up to renaming. Leading + * negations of both are tracked, so an axiom equal to the negated literal refutes it. + * + * @param literal a literal to decide + * @param axiom a literal assumed to be true + * @param services access to the theory operators + * @return {@code PROVED} if the axiom equals the literal, {@code REFUTED} if it equals its + * negation, otherwise {@code UNKNOWN} + */ + @Override + public LiteralDecision decideFromAxiom(JTerm literal, JTerm axiom, Services services) { + boolean negated = false; + JTerm pro = literal; + while (pro.op() == Junctor.NOT) { + pro = pro.sub(0); + negated = !negated; + } + JTerm ax = axiom; + while (ax.op() == Junctor.NOT) { + ax = ax.sub(0); + negated = !negated; + } + if (RENAMING_TERM_PROPERTY.equalsModThisProperty(pro, ax)) { + return negated ? LiteralDecision.REFUTED : LiteralDecision.PROVED; + } + return LiteralDecision.UNKNOWN; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/GenPolTieBreak.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/GenPolTieBreak.java new file mode 100644 index 00000000000..1faa773d32e --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/GenPolTieBreak.java @@ -0,0 +1,149 @@ +/* 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.quantifierHeuristics; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import de.uka.ilkd.key.ldt.JavaDLTheory; +import de.uka.ilkd.key.logic.op.ParametricFunctionInstance; +import de.uka.ilkd.key.logic.op.SkolemTermSV; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.rule.TacletApp; + +import org.key_project.logic.Term; +import org.key_project.logic.op.Function; +import org.key_project.logic.op.Operator; +import org.key_project.prover.rules.RuleApp; +import org.key_project.util.collection.ImmutableList; + +/** + * Orders tied instantiation candidates primarily by generation, that is by how late the + * instance's newest skolem constant was introduced on the branch, and breaks a same-generation + * tie by the + * proving-polarity occurrence connection of {@link PolarityOccurrenceTieBreak}. The tie-break of + * the {@code Good} quantifier treatment. + * + * Generation-primary keeps the sequent walk to a secondary role: it only decides between candidates + * of the same generation, which for the input constants of generation zero is the one large group. + */ +final class GenPolTieBreak extends PolarityOccurrenceTieBreak { + + static final GenPolTieBreak INSTANCE = new GenPolTieBreak(); + + private GenPolTieBreak() { + } + + @Override + public Scorer prepare(View view) { + final OccData occ = computeOccData(view); + final Map gen = computeGenerationRanks(view); + return inst -> generationValue(gen, inst) * (CAP + 1) + polarityValue(occ, inst); + } + + /** + * The generation rank of an instance: the introduction step of its newest skolem constant, or + * {@link #CAP} if the instance is not among the ranked candidates. + * + * @param ranks the rank per candidate + * @param inst the candidate instance + * @return the generation rank + */ + private static long generationValue(Map ranks, Term inst) { + Integer rank = ranks.get(inst); + if (rank == null && (inst.op() instanceof ParametricFunctionInstance pfi + && pfi.getBase().name().equals(JavaDLTheory.CAST_NAME))) { + rank = ranks.get(inst.sub(0)); + } + return rank == null ? CAP : rank; + } + + /** + * Ranks every candidate instance by the introduction step of its newest skolem constant. A + * candidate whose symbols all come from the problem input ranks 0, like a generation zero term + * of an SMT solver; the skolem-containing candidates follow in the order their newest symbol + * was + * introduced on the branch, capped by {@link #CAP}. All candidates' skolem constants are + * resolved in one walk over the branch's rule applications. + * + * @param view the instantiation view + * @return the rank per candidate + */ + private static Map computeGenerationRanks(View view) { + // the skolem constants occurring in each candidate + final Map> skolems = new LinkedHashMap<>(); + final Set wanted = new HashSet<>(); + final ArrayDeque todo = new ArrayDeque<>(); + for (final Term cand : view.candidates()) { + final List ops = new ArrayList<>(2); + todo.push(cand); + while (!todo.isEmpty()) { + final Term t = todo.pop(); + if (t.op() instanceof Function f && f.isSkolemConstant()) { + ops.add(f); + wanted.add(f); + } + for (int i = 0; i < t.arity(); i++) { + todo.push(t.sub(i)); + } + } + skolems.put(cand, ops); + } + // one walk over the branch: the introduction step of every wanted skolem constant. Unlike + // the introduction time of the arithmetic ordering this considers every taclet, so the + // delta-rule skolems are found as well. + final Map steps = new HashMap<>(); + if (!wanted.isEmpty()) { + final Goal goal = view.goal(); + ImmutableList applied = goal.appliedRuleApps(); + while (!applied.isEmpty() && steps.size() < wanted.size()) { + final RuleApp app = applied.head(); + applied = applied.tail(); + if (!(app instanceof TacletApp tapp)) { + continue; + } + for (final var entry : tapp.instantiations().getInstantiationMap()) { + if (!(entry.key() instanceof SkolemTermSV)) { + continue; + } + final Operator op = ((Term) entry.value().getInstantiation()).op(); + if (wanted.contains(op)) { + steps.putIfAbsent(op, applied.size()); + } + } + } + } + // newest skolem decides a candidate's introduction step; -1 = generation zero + final Map intro = new LinkedHashMap<>(); + final TreeSet distinct = new TreeSet<>(); + for (final var e : skolems.entrySet()) { + int max = -1; + for (final Operator op : e.getValue()) { + max = Math.max(max, steps.getOrDefault(op, -1)); + } + intro.put(e.getKey(), max); + if (max >= 0) { + distinct.add(max); + } + } + // ranks: generation zero -> 0, then 1, 2, ... in introduction order + final Map rankOf = new HashMap<>(); + int r = 1; + for (final Integer step : distinct) { + rankOf.put(step, Math.min(r++, CAP)); + } + final Map ranks = new LinkedHashMap<>(); + for (final var e : intro.entrySet()) { + ranks.put(e.getKey(), e.getValue() < 0 ? 0 : rankOf.get(e.getValue())); + } + return ranks; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java index d5cf4ad4bdc..ada457c2512 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArith.java @@ -42,7 +42,8 @@ private static Operator strippedOp(JTerm t) { /** Whether {@code t} (ignoring leading negations) is an integer {@code >=} or {@code <=}. */ private static boolean isArithComparison(JTerm t, IntegerLDT ig) { final Operator op = strippedOp(t); - return op == ig.getGreaterOrEquals() || op == ig.getLessOrEquals(); + return op == ig.getGreaterOrEquals() || op == ig.getLessOrEquals() + || op == ig.getLessThan() || op == ig.getGreaterThan(); } /** @@ -236,22 +237,40 @@ private static JTerm formatArithTerm(final JTerm problem, TermBuilder tb, Intege } final Function geq = ig.getGreaterOrEquals(); final Function leq = ig.getLessOrEquals(); + final Function lt = ig.getLessThan(); + final Function gt = ig.getGreaterThan(); + final Function add = ig.getAdd(); final JTerm falseT = tb.ff(); + // A strict comparison is rewritten to a non-strict one over the integers (a < b becomes + // a <= b - 1), so that all four comparisons reduce to the same >= form and can be + // compared as polynomials. sub(0) and sub(1) are the two compared terms. if (op == geq) { if (opNot) { - pro = tb.geq(pro.sub(1), tb.func(ig.getAdd(), pro.sub(0), ig.one())); + pro = tb.geq(pro.sub(1), tb.func(add, pro.sub(0), ig.one())); } - } else { - if (op == leq) { - if (opNot) { - pro = tb.geq(pro.sub(0), tb.func(ig.getAdd(), pro.sub(1), ig.one())); - } else { - pro = tb.geq(pro.sub(1), pro.sub(0)); - } + } else if (op == leq) { + if (opNot) { + pro = tb.geq(pro.sub(0), tb.func(add, pro.sub(1), ig.one())); + } else { + pro = tb.geq(pro.sub(1), pro.sub(0)); + } + } else if (op == lt) { + // a < b is b >= a + 1; its negation is a >= b + if (opNot) { + pro = tb.geq(pro.sub(0), pro.sub(1)); } else { - pro = falseT; + pro = tb.geq(pro.sub(1), tb.func(add, pro.sub(0), ig.one())); } + } else if (op == gt) { + // a > b is a >= b + 1; its negation is b >= a + if (opNot) { + pro = tb.geq(pro.sub(1), pro.sub(0)); + } else { + pro = tb.geq(pro.sub(0), tb.func(add, pro.sub(1), ig.one())); + } + } else { + pro = falseT; } putInTermCache(formattedTermCache, problem, pro); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeapArrayTheorySupport.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeapArrayTheorySupport.java new file mode 100644 index 00000000000..199afb85e17 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeapArrayTheorySupport.java @@ -0,0 +1,160 @@ +/* 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.quantifierHeuristics; + +import java.util.ArrayList; +import java.util.List; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.java.transformations.pipeline.PipelineConstants; +import de.uka.ilkd.key.ldt.HeapLDT; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.sort.ArraySort; + +import org.key_project.logic.Name; +import org.key_project.logic.op.QuantifiableVariable; +import org.key_project.logic.sort.Sort; +import org.key_project.util.collection.ImmutableSet; + +/** + * Support for the heap theory and array reads. + * + * Rejects the bare array-index constructor {@code arr(i)} (a coordinate, not a read) and reads of + * the implicit {@code $created} field, and provides array-read triggers generalized over the heap + * so that a read written for one heap in a quantified formula matches the reads a proof produces + * over its many other heaps. + */ +final class HeapArrayTheorySupport implements QuantifierTheorySupport { + + /** + * Rejects the bare array index {@code arr(i)} and reads of the implicit created field, both of + * which flood the instantiation when matched on their own. + * + * @param candidate a trigger candidate that contains the quantified variables + * @param services access to the heap theory operators + * @return whether the candidate is rejected + */ + @Override + public boolean rejectsAsTrigger(JTerm candidate, Services services) { + final HeapLDT heapLDT = services.getTypeConverter().getHeapLDT(); + // we do not want to match on expressions a.$created + if (heapLDT.isSelectOp(candidate.op()) && candidate.sub(2).op().name().toString() + .endsWith(PipelineConstants.IMPLICIT_CREATED)) { + return true; + } + // the array-index constructor arr(i) alone is a coordinate, not a read: matching on it + // instantiates with every index literal of any array on any heap. The enclosing select is + // the meaningful trigger (see the generalized variants provided below). + return candidate.op() == heapLDT.getArr(); + } + + /** + * Provides the heap-generalized array read triggers, one per array dimension of the read. + * + * @param term an accepted trigger term + * @param clauseVariables the quantified variables of the clause the trigger belongs to + * @param services access to the heap theory operators and term construction + * @return the generalized read triggers, possibly empty + */ + @Override + public List provideTriggers(JTerm term, + ImmutableSet clauseVariables, Services services) { + return dimensionVariants(term, clauseVariables, services); + } + + /** + * The generalized triggers for an array read, one per array dimension it goes through. This + * is the single generalization path: for a one-dimensional read it yields one trigger, for a + * read through a multi-dimensional array one per level. + * + * Two things must be generalized. The heap, because after simplification the read occurs over + * the many heaps of a proof (store chains of symbolic execution, an anonymized loop heap), + * not only the one written in the formula; a fresh metavariable per level stands for any heap. + * And the select sorts, because a formula may read {@code x[i][i_1]} with sorts of its own + * choice (a nonNull specification types the final read as plain Object), while the ground reads + * in a sequent are built with the component sorts of {@code x}'s array type, one per dimension. + * A trigger carrying the formula's sorts never matches: parametric selects of different sorts + * are different functions. + * + * For a select chain over an array-sorted base this method therefore rebuilds the access path + * once per depth, with the component sort of the base's array type at that depth and a fresh + * heap wildcard per level: for {@code x[i][i_1]} the triggers {@code x[i]} and + * {@code x[i][i_1]}, each carrying the sorts a ground read of that depth actually has. Prefixes + * that bind only part of the clause variables enter the multi-trigger pool as usual. + * + * @param term an accepted array read trigger + * @param clauseVariables the quantified variables of the clause the trigger belongs to + * @param services access to the heap theory operators and term construction + * @return one generalized read trigger per array dimension, possibly empty + */ + private List dimensionVariants(JTerm term, + ImmutableSet clauseVariables, Services services) { + final HeapLDT heapLDT = services.getTypeConverter().getHeapLDT(); + final TermBuilder tb = services.getTermBuilder(); + final List variants = new ArrayList<>(); + // decompose the select chain: walk through the object position collecting the arr + // coordinates, innermost first + final List coordinates = new ArrayList<>(); + JTerm base = term; + while (heapLDT.isSelectOp(base.op()) && base.sub(2).op() == heapLDT.getArr()) { + coordinates.add(0, base.sub(2).sub(0)); + base = base.sub(1); + } + if (coordinates.isEmpty() || !(base.sort() instanceof ArraySort)) { + return variants; + } + boolean anyVar = false; + for (final JTerm c : coordinates) { + if (!TriggerUtils.intersect(c.freeVars(), clauseVariables).isEmpty()) { + anyVar = true; + } + } + if (!anyVar) { + return variants; + } + // rebuild the path bottom-up with the array's component sorts + Sort sort = base.sort(); + JTerm read = base; + for (int depth = 0; depth < coordinates.size(); depth++) { + if (!(sort instanceof ArraySort arraySort)) { + break; + } + sort = arraySort.elementSort(); + final JTerm heapVar = + tb.var(heapWildcard(term, clauseVariables, heapLDT.targetSort(), "_d" + depth)); + final JTerm arrField = tb.func(heapLDT.getArr(), coordinates.get(depth)); + read = tb.select(sort, heapVar, read, arrField); + if (!TriggerUtils.intersect(read.freeVars(), clauseVariables).isEmpty() + && !read.equals(term)) { + variants.add(read); + } + } + return variants; + } + + /** + * A fresh heap-sorted metavariable standing for "any heap" in a generalized trigger. Its name + * is derived from the quantified variables of the read (plus a caller-chosen suffix to keep + * several wildcards of one trigger apart) rather than from creation order, so that the + * metavariable ordering (and through it the unification result and the chosen instances) does + * not depend on which goal builds its trigger set first. + * + * @param select the read the wildcard is built for + * @param clauseVariables the quantified variables of the clause the read belongs to + * @param heapSort the sort of heaps + * @param suffix keeps several wildcards of one trigger apart + * @return a fresh heap-sorted metavariable + */ + private static Metavariable heapWildcard(JTerm select, + ImmutableSet clauseVariables, Sort heapSort, String suffix) { + final StringBuilder name = new StringBuilder("heapWildcard"); + for (final QuantifiableVariable v : TriggerUtils.intersect(select.freeVars(), + clauseVariables)) { + name.append('_').append(v.name()); + } + name.append(suffix); + return new Metavariable(new Name(name.toString()), heapSort); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java index 143ebb5731a..34e396264b6 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java @@ -52,6 +52,53 @@ private Instantiation(Term allterm, Sequent seq, Services services) { triggersSet = TriggersSet.create((JTerm) allterm, services); assumedLiterals = initAssertLiterals(seq, services); addInstances(sequentToTerms(seq), services); + addStoreCoordinateInstances((JTerm) matrix, services); + } + + /** + * Heap-aware instance candidates from write coordinates: where the matrix reads an array + * through a built-up heap, {@code select(... store(h, o, arr(c), v) ..., o, arr(j))} with + * quantified index {@code j}, the written index {@code c} is a candidate for {@code j}. + * Instantiating with it lets the select collapse by the select-over-store rules, which is + * how such a quantified formula speaks about the stored value. Trigger matching cannot + * produce these candidates: the store coordinate contains no quantified variable, so no + * trigger binds {@code j} to it. The candidates go through the same cost computation as + * matched ones, so useless coordinates are excluded or ranked down as usual. + */ + private void addStoreCoordinateInstances(JTerm term, Services services) { + final var heapLDT = services.getTypeConverter().getHeapLDT(); + // isSelectOp tests the operator directly. Do not build getSelect(term.sort()): that + // constructs a select of the subterm's sort, which fails for e.g. the Null sort. + if (heapLDT.isSelectOp(term.op())) { + final JTerm field = term.sub(2); + if (field.op() == heapLDT.getArr() && field.freeVars().contains(firstVar)) { + collectWrittenIndices(term.sub(0), term.sub(1), services); + } + } + for (int i = 0; i < term.arity(); i++) { + addStoreCoordinateInstances(term.sub(i), services); + } + } + + /** Adds every ground index written on {@code obj}'s array fields in {@code heap}. */ + private void collectWrittenIndices(JTerm heap, JTerm obj, Services services) { + final var heapLDT = services.getTypeConverter().getHeapLDT(); + if (heap.sort() != heapLDT.targetSort()) { + return; + } + if (heap.op() == heapLDT.getStore()) { + final JTerm field = heap.sub(2); + if (heap.sub(1).equals(obj) && field.op() == heapLDT.getArr() + && field.freeVars().isEmpty()) { + final ImmutableMap varMap = + DefaultImmutableMap.nilMap() + .put(firstVar, field.sub(0)); + addInstance(new Substitution(varMap), services); + } + } + for (int i = 0; i < heap.arity(); i++) { + collectWrittenIndices(heap.sub(i), obj, services); + } } private record Cached(Term qf, Sequent seq, Instantiation result) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/IntegerTheorySupport.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/IntegerTheorySupport.java new file mode 100644 index 00000000000..76e6fb18dd5 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/IntegerTheorySupport.java @@ -0,0 +1,122 @@ +/* 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.quantifierHeuristics; + +import java.util.List; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.ldt.IntegerLDT; +import de.uka.ilkd.key.logic.JTerm; + +import org.key_project.logic.op.Operator; +import org.key_project.logic.op.QuantifiableVariable; +import org.key_project.util.collection.ImmutableSet; + +/** + * Support for the integer theory. + * + * Rejects the (non-strict) comparisons as triggers (matching on them has not been observed to help + * instantiation) and provides no derived triggers. For cost prediction it decides an arithmetic + * comparison from itself or from an assumed comparison, through {@link HandleArith}. + */ +final class IntegerTheorySupport implements QuantifierTheorySupport { + + /** + * Rejects the non-strict comparisons {@code <=} and {@code >=} as triggers. + * + * @param candidate a trigger candidate that contains the quantified variables + * @param services access to the integer theory operators + * @return whether the candidate is rejected + */ + @Override + public boolean rejectsAsTrigger(JTerm candidate, Services services) { + final Operator op = candidate.op(); + final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); + return op == integerLDT.getLessOrEquals() || op == integerLDT.getGreaterOrEquals(); + } + + /** + * Provides no derived triggers. + * + * @param term an accepted trigger term + * @param clauseVariables the quantified variables of the clause the trigger belongs to + * @param services access to the integer theory operators + * @return the empty list + */ + @Override + public List provideTriggers(JTerm term, + ImmutableSet clauseVariables, Services services) { + return List.of(); + } + + /** + * Checks whether an arithmetic comparison holds on its own, through {@link HandleArith}. + * + * @param strippedLiteral a literal without leading negations + * @param services access to the integer theory operators + * @return the arithmetic verdict, or {@code UNKNOWN} if undecided + */ + @Override + public LiteralDecision decideStrippedSelf(JTerm strippedLiteral, Services services) { + final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); + return QuantifierTheorySupport + .fromTruthTerm(HandleArith.provedByArith(strippedLiteral, integerLDT, services)); + } + + /** + * Checks whether an arithmetic comparison follows from an assumed comparison, through + * {@link HandleArith}. + * + * @param literal a literal to decide + * @param axiom a literal assumed to be true + * @param services access to the integer theory operators + * @return the arithmetic verdict, or {@code UNKNOWN} if undecided + */ + @Override + public LiteralDecision decideFromAxiom(JTerm literal, JTerm axiom, Services services) { + final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); + return QuantifierTheorySupport + .fromTruthTerm(HandleArith.provedByArith(literal, axiom, integerLDT, services)); + } + + /** + * Restricts the equality normalisation on integer terms to what the arithmetic decisions + * tolerate. A number literal is never rewritten away: it is the concrete value the comparisons + * in {@link HandleArith} are decided on. A term built by the polynomial operators is left in + * place in both directions: rewriting it away collapses the structure that + * {@link de.uka.ilkd.key.rule.metaconstruct.arith.Polynomial} decomposes, and rewriting other + * terms into it makes it a class representative, which the one-pass normalisation of + * {@link Congruence} does not rewrite further. Rewriting an atom to a number literal or to + * another atom stays permitted: that only identifies atoms, which the assumed equality + * justifies, and can only add arithmetic decisions. + * + * @param from the term whose occurrences would be rewritten + * @param to the replacement term + * @param services access to the integer theory operators + * @return whether the rewrite keeps the arithmetic forms intact + */ + @Override + public boolean allowsEqualityRewrite(JTerm from, JTerm to, Services services) { + final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); + if (from.op() == integerLDT.getNumberSymbol()) { + return false; + } + return !hasPolynomialStructure(from, integerLDT) && !hasPolynomialStructure(to, integerLDT); + } + + /** + * Whether the term's top operator is one the polynomial decomposition takes apart. Besides the + * sum and product this covers difference and negation, which the proof search rewrites into + * them. + * + * @param t a term + * @param integerLDT the integer theory operators + * @return whether the top operator carries polynomial structure + */ + private static boolean hasPolynomialStructure(JTerm t, IntegerLDT integerLDT) { + final Operator op = t.op(); + return op == integerLDT.getAdd() || op == integerLDT.getMul() + || op == integerLDT.getSub() || op == integerLDT.getNeg(); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/MultiTrigger.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/MultiTrigger.java index aebec8f52c0..7dfbe159404 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/MultiTrigger.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/MultiTrigger.java @@ -37,6 +37,11 @@ class MultiTrigger implements Trigger { this.clause = clause; } + /** The uni-trigger elements that jointly cover the clause variables. */ + ImmutableSet elements() { + return elements; + } + @Override public ImmutableSet getSubstitutionsFromTerms(ImmutableSet targetTerms, Services services) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityOccurrenceTieBreak.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityOccurrenceTieBreak.java new file mode 100644 index 00000000000..db8e0a073c5 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityOccurrenceTieBreak.java @@ -0,0 +1,331 @@ +/* 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.quantifierHeuristics; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.ldt.JavaDLTheory; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.op.Equality; +import de.uka.ilkd.key.logic.op.IfThenElse; +import de.uka.ilkd.key.logic.op.Junctor; +import de.uka.ilkd.key.logic.op.ParametricFunctionInstance; +import de.uka.ilkd.key.logic.op.Quantifier; +import de.uka.ilkd.key.proof.Proof; + +import org.key_project.logic.Term; +import org.key_project.logic.op.Modality; +import org.key_project.logic.op.Operator; +import org.key_project.prover.sequent.Sequent; +import org.key_project.prover.sequent.SequentFormula; + +import static de.uka.ilkd.key.logic.equality.IrrelevantTermLabelsProperty.IRRELEVANT_TERM_LABELS_PROPERTY; + +/** + * The shared machinery of the occurrence-based tie-breaks. Both {@link PolarityTieBreak} and the + * secondary of {@link GenPolTieBreak} order candidates by how strongly an instance is connected to + * the sequent, giving occurrences at proving polarity twice the weight. This base owns the walk + * that produces those counts and the {@link #polarityValue} that reads them; the subclasses only + * combine. + * + * The counts are collected per sequent formula: which operators occur in the formula, and which at + * relative proving polarity. A sequent step replaces few formulas and the + * {@link SequentFormula} objects are immutable and shared along a branch, so the per-formula + * summary is memoised in {@link de.uka.ilkd.key.java.ServiceCaches}. The per-sequent aggregation is + * memoised once more in a thread-local, so all quantified formulas of one sequent reuse it. + */ +abstract class PolarityOccurrenceTieBreak implements QuantifierInstantiationTieBreak { + + /** The largest tie-break value; an instance in this many or more formulas gets the value 0. */ + static final int CAP = 15; + + /** + * The occurrence counts of a candidate set: formulas per instance, proving-polarity per + * instance. + */ + record OccData(Map occ, Map goalOcc) { + } + + /** + * Collects the occurrence counts of the view's candidates: for each candidate the number of + * sequent formulas it occurs in, and for a constant candidate the number where it occurs at + * proving polarity. Compound candidates are counted exactly, capped, in one walk shared by all. + * + * @param view the instantiation view + * @return the occurrence counts + */ + protected static OccData computeOccData(View view) { + final Map occ = new LinkedHashMap<>(); + final Map goalOcc = new LinkedHashMap<>(); + final Collection candidates = view.candidates(); + if (candidates.isEmpty()) { + return new OccData(occ, goalOcc); + } + final Sequent seq = view.sequent(); + final SequentCounts counts = sequentCounts(seq, view.services()); + final List unknown = new ArrayList<>(); + for (final Term cand : candidates) { + if (cand.arity() == 0) { + occ.put(cand, counts.opCounts().getOrDefault(cand.op(), 0)); + goalOcc.put(cand, counts.goalCounts().getOrDefault(cand.op(), 0)); + } else { + final Integer known = counts.compoundCounts().get(cand); + if (known != null) { + occ.put(cand, known); + } else { + unknown.add(cand); + } + } + } + if (!unknown.isEmpty()) { + countCompounds(seq, unknown, counts.compoundCounts()); + for (final Term cand : unknown) { + // store a zero for candidates never found, so they are not counted again for the + // next quantified formula of this sequent + counts.compoundCounts().putIfAbsent(cand, 0); + occ.put(cand, counts.compoundCounts().get(cand)); + } + } + return new OccData(occ, goalOcc); + } + + /** + * The occurrence value of an instance with the proving-polarity boost: a formula where the + * instance occurs at proving polarity counts twice, so of two equally frequent instances the + * one the proof still has to say something about comes first. A weakly connected instance gets + * a + * large value, a strongly connected one a small value, bounded by {@link #CAP}. + * + * @param d the occurrence counts + * @param inst the candidate instance + * @return the boosted occurrence value, between 0 and {@link #CAP} + */ + protected static long polarityValue(OccData d, Term inst) { + Integer occ = d.occ().get(inst); + Integer pos = d.goalOcc().get(inst); + if (occ == null && (inst.op() instanceof ParametricFunctionInstance pfi + && pfi.getBase().name().equals(JavaDLTheory.CAST_NAME))) { + occ = d.occ().get(inst.sub(0)); + pos = d.goalOcc().get(inst.sub(0)); + } + if (occ == null) { + return CAP; + } + final int boosted = occ + (pos == null ? 0 : pos); + return Math.max(0, CAP - Math.min(boosted, CAP)); + } + + // ------------------------------------------------------------------------ + // the per-formula walk and its two caches + // ------------------------------------------------------------------------ + + /** Offset making a formula-layer polarity (-1, 0, +1) a non-negative walk state. */ + private static final int FORMULA_BASE = 1; + /** Offset marking a frozen polarity; states at or above it no longer flip. */ + private static final int FROZEN_BASE = 4; + + /** The formula count per operator and the proving-polarity formula count per operator. */ + private record SequentCounts(Proof proof, Sequent seq, Map opCounts, + Map goalCounts, Map compoundCounts) { + } + + /** + * The operator sets of a single sequent formula, all polarities relative to the formula root: + * the operators occurring in it, and those occurring at relative proving polarity {@code +1} + * respectively {@code -1} (in a non-connective position). + */ + record OccInfo(Set opsAny, Set opsRelPlus, + Set opsRelMinus) { + } + + /** + * Per-thread single-entry cache for {@link #sequentCounts}, so all quantified formulas of one + * sequent reuse the aggregation. + */ + private static final ThreadLocal lastCounts = new ThreadLocal<>(); + + /** + * The occurrence knowledge of the sequent, aggregated from the per-formula summaries: the + * number + * of formulas each operator occurs in, and the number where it occurs at proving polarity + * (succedent at relative {@code +1}, antecedent at relative {@code -1}). + */ + private static SequentCounts sequentCounts(Sequent seq, Services services) { + final Proof proof = services.getProof(); + final SequentCounts cached = lastCounts.get(); + if (cached != null && cached.seq() == seq) { + return cached; + } + if (cached != null && proof != cached.proof()) { + // The memo belongs to another proof. Drop it before computing, so the other + // proof's sequent stays reachable only while this entry is in use. + lastCounts.remove(); + } + final Map counts = new HashMap<>(); + final Map goal = new HashMap<>(); + boolean antec = true; + int rows = seq.antecedent().size(); + for (final SequentFormula cf : seq) { + if (rows-- == 0) { + antec = false; + } + final OccInfo info = occInfo(cf, services); + for (final Operator op : info.opsAny()) { + counts.merge(op, 1, Integer::sum); + } + for (final Operator op : antec ? info.opsRelMinus() : info.opsRelPlus()) { + goal.merge(op, 1, Integer::sum); + } + } + final SequentCounts result = + new SequentCounts(proof, seq, counts, goal, new LinkedHashMap<>()); + lastCounts.set(result); + return result; + } + + /** + * The operator summary of a sequent formula, computed once per formula and cached. The walk + * pairs each subterm with its polarity relative to the formula root, following the rules of the + * taclet application restrictions: the root is proving ({@code +1}), a negation and the left + * side of an implication flip, conjunction, disjunction, the right side of an implication and + * the branches of a conditional keep, everything else (equivalences, quantifiers, modalities) + * is + * neutral. The polarity is frozen when the walk enters an atom. State encoding: polarity+1 for + * the formula layer, polarity+4 once frozen. + */ + /** The walk state of a formula-layer position: the polarity shifted to be non-negative. */ + private static int formulaState(int polarity) { + return polarity + FORMULA_BASE; + } + + /** The walk state below an atom: the polarity is frozen and no longer flips. */ + private static int frozenState(int polarity) { + return polarity + FROZEN_BASE; + } + + static OccInfo occInfo(SequentFormula cf, Services services) { + final Map cache = services.getCaches().getFormulaOccurrenceCache(); + final Object hit = cache.get(cf); + if (hit != null) { + return (OccInfo) hit; + } + final Set opsAny = new HashSet<>(); + final Set relPlus = new HashSet<>(); + final Set relMinus = new HashSet<>(); + final ArrayDeque todo = new ArrayDeque<>(); + final ArrayDeque todoState = new ArrayDeque<>(); + final Map visitedMask = new HashMap<>(); + todo.push(cf.formula()); + todoState.push(formulaState(1)); + while (!todo.isEmpty()) { + final Term t = todo.pop(); + final int state = todoState.pop(); + final Integer seen = visitedMask.get(t); + final int bit = 1 << state; + if (seen != null && (seen & bit) != 0) { + continue; + } + visitedMask.put(t, seen == null ? bit : seen | bit); + final boolean frozen = state >= frozenState(-1); + final int pol = frozen ? state - FROZEN_BASE : state - FORMULA_BASE; + final Operator op = t.op(); + opsAny.add(op); + if (frozen || !isConnective(op)) { + if (pol == 1) { + relPlus.add(op); + } else if (pol == -1) { + relMinus.add(op); + } + } + for (int i = 0; i < t.arity(); i++) { + final int childState; + if (frozen) { + childState = state; + } else if (op == Junctor.NOT || (op == Junctor.IMP && i == 0)) { + childState = formulaState(-pol); + } else if (op == Junctor.AND || op == Junctor.OR + || (op == Junctor.IMP && i != 0)) { + childState = formulaState(pol); + } else if (op == IfThenElse.IF_THEN_ELSE) { + childState = i == 0 ? formulaState(0) : formulaState(pol); + } else if (op instanceof Modality || op == Quantifier.ALL || op == Quantifier.EX + || op == Equality.EQV) { + childState = formulaState(0); + } else { + // atom boundary: the enclosing formula's polarity holds below + childState = frozenState(pol); + } + todo.push(t.sub(i)); + todoState.push(childState); + } + } + final OccInfo info = new OccInfo(opsAny, relPlus, relMinus); + cache.put(cf, info); + return info; + } + + /** Whether the operator belongs to the formula layer the polarity walk toggles through. */ + private static boolean isConnective(Operator op) { + return op == Junctor.NOT || op == Junctor.AND || op == Junctor.OR || op == Junctor.IMP + || op == Junctor.TRUE || op == Junctor.FALSE || op == IfThenElse.IF_THEN_ELSE; + } + + /** + * Counts the given compound candidates over the sequent's formulas. Each formula is walked once + * over its distinct subterms; a subterm matches a candidate up to term labels. A candidate + * reaching {@link #CAP} formulas is done and leaves the walk, and the walk ends when no + * candidate + * is left. + */ + private static void countCompounds(Sequent seq, List unknown, + Map results) { + final List active = new ArrayList<>(unknown); + final ArrayDeque todo = new ArrayDeque<>(); + final Set visited = new HashSet<>(); + // Insertion-ordered: the counts below are merged in hit order. + final Set hits = new LinkedHashSet<>(); + for (final SequentFormula cf : seq) { + if (active.isEmpty()) { + break; + } + visited.clear(); + hits.clear(); + todo.push(cf.formula()); + while (!todo.isEmpty() && hits.size() < active.size()) { + final Term t = todo.pop(); + if (!visited.add(t)) { + continue; + } + for (final Term c : active) { + // Terms equal up to labels share the cached name hash, so the hash compare + // rejects almost every pair before the structural comparison. + if (t.nameHash() == c.nameHash() && !hits.contains(c) + && ((JTerm) t).equalsModProperty(c, IRRELEVANT_TERM_LABELS_PROPERTY)) { + hits.add(c); + } + } + for (int i = 0; i < t.arity(); i++) { + todo.push(t.sub(i)); + } + } + todo.clear(); + for (final Term c : hits) { + final int n = results.merge(c, 1, Integer::sum); + if (n >= CAP) { + active.remove(c); + } + } + } + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityTieBreak.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityTieBreak.java new file mode 100644 index 00000000000..c6db279692c --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityTieBreak.java @@ -0,0 +1,23 @@ +/* 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.quantifierHeuristics; + +/** + * Orders tied instantiation candidates by their proving-polarity connection to the sequent (see + * {@link PolarityOccurrenceTieBreak#polarityValue}). The tie-break of the {@code Best} quantifier + * treatment. + */ +final class PolarityTieBreak extends PolarityOccurrenceTieBreak { + + static final PolarityTieBreak INSTANCE = new PolarityTieBreak(); + + private PolarityTieBreak() { + } + + @Override + public Scorer prepare(View view) { + final OccData d = computeOccData(view); + return inst -> polarityValue(d, inst); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java index 11ed848decb..588fc1ae351 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProver.java @@ -10,19 +10,18 @@ import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.TermBuilder; -import de.uka.ilkd.key.logic.op.Equality; import de.uka.ilkd.key.logic.op.Junctor; -import org.key_project.logic.Term; import org.key_project.logic.op.Operator; import org.key_project.util.collection.DefaultImmutableSet; import org.key_project.util.collection.ImmutableSet; -import static de.uka.ilkd.key.logic.equality.IrrelevantTermLabelsProperty.IRRELEVANT_TERM_LABELS_PROPERTY; -import static de.uka.ilkd.key.logic.equality.RenamingTermProperty.RENAMING_TERM_PROPERTY; - /** - * TODO: rewrite, this seems pretty inefficient ... + * Predicts the cost of instantiating a quantified formula with a candidate term. The instantiated + * matrix is read as a conjunction of clauses. Each clause is refined against the literals already + * known true on the sequent, dropping a literal that is false and marking the clause true once one + * of its literals is proved. The predicted cost combines the sizes of the clauses that remain, so + * an instantiation that leaves fewer open clauses is cheaper. */ public class PredictCostProver { @@ -30,41 +29,125 @@ public class PredictCostProver { private final JTerm trueT, falseT; - /** assume that all literal in assertLiterals are true */ + /** The literals assumed to be true on the sequent. */ private ImmutableSet assertLiterals; - /** clauses from instance of CNF */ + /** The clauses of the instantiated matrix, a conjunction of disjunctions. */ private Set clauses = new LinkedHashSet<>(); private final Services services; - /** the integer theory, fetched once because a prediction judges many literals in a row */ - private final de.uka.ilkd.key.ldt.IntegerLDT integerLDT; + /** + * Equality reasoning over the sequent's assumed equalities, built once and shared across the + * cost predictions of all candidate instantiations. Lets a clause literal already satisfied by + * an assumed equality be recognised, so the instance is not proposed as a useful step. + */ + private final Congruence congruence; - private PredictCostProver(JTerm instance, ImmutableSet assertList, Services services) { + private PredictCostProver(JTerm instance, ImmutableSet assertList, Congruence congruence, + Services services) { this.assertLiterals = assertList; + this.congruence = congruence; this.services = services; - this.integerLDT = services.getTypeConverter().getIntegerLDT(); this.tb = services.getTermBuilder(); this.trueT = tb.tt(); this.falseT = tb.ff(); initClauses(instance); } - public static long computerInstanceCost(Substitution sub, JTerm matrix, - ImmutableSet assertList, Services services) { + /** + * Predicts the cost of instantiating a quantified formula's matrix with a candidate + * substitution. + * + * @param sub a ground substitution for the quantified variables + * @param matrix the matrix of the quantified formula + * @param assertList the literals assumed to be true on the sequent, already normalised through + * {@code congruence} + * @param congruence equality reasoning over the sequent's assumed equalities + * @param services access to the theory operators + * @return the predicted cost, or -1 if the substitution is not ground or every clause is proved + * true + */ + static long computerInstanceCost(Substitution sub, JTerm matrix, + ImmutableSet assertList, Congruence congruence, Services services) { if (!sub.isGround()) { // non-ground substitutions not supported yet return -1; } else { final PredictCostProver prover = new PredictCostProver( - (JTerm) sub.applyWithoutCasts(matrix, services), assertList, services); + (JTerm) sub.applyWithoutCasts(matrix, services), assertList, congruence, services); return prover.cost(); } } - // init context + /** + * The axioms of one sequent prepared for repeated predictions: the congruence built from + * them and the literals normalized by it. Opaque outside this package, so the congruence + * type stays internal; build once per sequent and reuse for every candidate instance. + */ + public static final class PreparedAxioms { + private final Congruence congruence; + private final ImmutableSet normalized; + + private PreparedAxioms(Congruence congruence, ImmutableSet normalized) { + this.congruence = congruence; + this.normalized = normalized; + } + } + + /** + * Prepares the given literals for repeated predictions over one sequent. + * + * @param assertList the literals assumed to be true on the sequent + * @param services access to the theory operators + * @return the prepared axioms + */ + public static PreparedAxioms prepare(ImmutableSet assertList, Services services) { + final Congruence congruence = new Congruence(assertList, services); + ImmutableSet normalized = assertList; + if (!congruence.isTrivial()) { + ImmutableSet res = DefaultImmutableSet.nil(); + for (final JTerm lit : assertList) { + res = res.add(congruence.normalize(lit)); + } + normalized = res; + } + return new PreparedAxioms(congruence, normalized); + } + + /** + * As the congruence-taking entry point, with the axioms prepared by {@link #prepare}. + * + * @param sub a ground substitution for the quantified variables + * @param matrix the matrix of the quantified formula + * @param axioms the prepared axioms of the sequent + * @param services access to the theory operators + * @return the predicted cost, or -1 if the substitution is not ground or every clause is + * proved true + */ + public static long computerInstanceCost(Substitution sub, JTerm matrix, PreparedAxioms axioms, + Services services) { + return computerInstanceCost(sub, matrix, axioms.normalized, axioms.congruence, services); + } + + /** + * Convenience entry point for callers without a shared congruence: builds one from + * {@code assertList} and normalises the literals, then predicts the cost. The quantifier + * instantiation path shares one congruence per sequent instead and calls the overload above. + * + * @param sub a ground substitution for the quantified variables + * @param matrix the matrix of the quantified formula + * @param assertList the literals assumed to be true on the sequent + * @param services access to the theory operators + * @return the predicted cost + */ + public static long computerInstanceCost(Substitution sub, JTerm matrix, + ImmutableSet assertList, Services services) { + return computerInstanceCost(sub, matrix, prepare(assertList, services), services); + } + + /** Splits the instantiated matrix into its clauses. */ private void initClauses(JTerm instance) { for (var t : TriggerUtils.setByOperator(instance, Junctor.AND)) { @@ -75,6 +158,12 @@ private void initClauses(JTerm instance) { } } + /** + * Gathers the disjuncts of a clause into a literal set. + * + * @param set the disjuncts of a clause + * @return the clause's literals, wrapped in a one-element set + */ private ImmutableSet> createClause( ImmutableSet set) { final ImmutableSet> nil = DefaultImmutableSet.nil(); @@ -89,119 +178,111 @@ private ImmutableSet> createClause( return res; } - // end - - // (2)self-proved rule /** - * If the given problem's operation is equal,or mathmetic operation(=,>=, <=), this - * method will try to prove it by finding the relation between its two subterms. + * Checks whether problem holds on its own. The literal is stripped of its leading + * negations and offered to each theory support; the first support that reaches a verdict wins, + * and the stripped negations are re-applied to it. + * + * @param problem the literal to decide + * @return trueT if the literal is proved true, falseT if proved + * false, + * and problem if undecided */ private JTerm provedBySelf(JTerm problem) { boolean negated = false; JTerm pro = problem; - Operator op = pro.op(); - while (op == Junctor.NOT) { + while (pro.op() == Junctor.NOT) { negated = !negated; pro = pro.sub(0); - op = pro.op(); } - if ((op == Equality.EQUALS || op == Equality.EQV)) { - Term term = pro.sub(0); - Term formula = pro.sub(1); - if (RENAMING_TERM_PROPERTY.equalsModThisProperty(term, formula)) { - return negated ? falseT : trueT; + for (final QuantifierTheorySupport support : TriggersSet.THEORY_SUPPORTS) { + QuantifierTheorySupport.LiteralDecision decision = + support.decideStrippedSelf(pro, services); + if (decision != QuantifierTheorySupport.LiteralDecision.UNKNOWN) { + if (negated) { + decision = decision.negate(); + } + return decision == QuantifierTheorySupport.LiteralDecision.PROVED ? trueT : falseT; } } - JTerm arithRes = HandleArith.provedByArith(pro, integerLDT, services); - if (TriggerUtils.isTrueOrFalse(arithRes)) { - return negated ? tb.not(arithRes) : arithRes; - } else { - return problem; - } - } - - // (3)equal rule - /*** - * @return trueT if problem is equal axiom, false if problem's negation is equal axiom. - * Otherwise retrun problem. - */ - private JTerm directConsequenceOrContradictionOfAxiom(JTerm problem, JTerm axiom) { - boolean negated = false; - JTerm pro = problem; - while (pro.op() == Junctor.NOT) { - pro = pro.sub(0); - negated = !negated; - } - JTerm ax = axiom; - while (ax.op() == Junctor.NOT) { - ax = ax.sub(0); - negated = !negated; - } - if (RENAMING_TERM_PROPERTY.equalsModThisProperty(pro, ax)) { - return negated ? falseT : trueT; - } return problem; } - // (4)combine provedByequal and provedByArith . /** - * @param problem - * @param axiom - * @return if axiom conduct problem then return trueT. If axiom conduct negation of problem - * return fastT. Otherwise, return problem + * Checks whether problem follows from the assumed-true axiom by + * offering both to each theory support. The first support that reaches a verdict wins. + * + * @param problem the literal to decide + * @param axiom a literal assumed to be true + * @return trueT if the axiom proves the problem, falseT if it proves + * the problem's negation, and problem if undecided */ private JTerm provedByAnother(JTerm problem, JTerm axiom) { - JTerm res = directConsequenceOrContradictionOfAxiom(problem, axiom); - if (TriggerUtils.isTrueOrFalse(res)) { - return res; + for (final QuantifierTheorySupport support : TriggersSet.THEORY_SUPPORTS) { + final QuantifierTheorySupport.LiteralDecision decision = + support.decideFromAxiom(problem, axiom, services); + if (decision != QuantifierTheorySupport.LiteralDecision.UNKNOWN) { + return decision == QuantifierTheorySupport.LiteralDecision.PROVED ? trueT : falseT; + } } - return HandleArith.provedByArith(problem, axiom, integerLDT, services); + return problem; } - // (5) combine rules /** - * try to prove problem by know assertLits + * Checks whether problem holds, first on its own and then from each assumed + * literal + * in turn. * - * @param problem a literal to be proved - * @param assertLits a set of term assertLiterals in which all literals are true - * @return return trueT if if formu is proved to true, falseT if - * false, and atom if it cann't be proved. + * @param problem a literal to decide + * @param assertLits literals assumed to be true + * @return trueT if the literal is proved true, falseT if proved + * false, + * and the literal itself if neither */ private JTerm proveLiteral(JTerm problem, Iterable assertLits) { - JTerm res; - /* - * res = provedFromCache(problem, cache); if (res.equals(trueT) || res.equals(falseT)) { - * return res; } - */ - res = provedBySelf(problem); + final JTerm normProblem = congruence.normalize(problem); + JTerm res = provedBySelf(normProblem); if (TriggerUtils.isTrueOrFalse(res)) { - // addToCache(problem,res,cache); return res; } for (JTerm t : assertLits) { - res = provedByAnother(problem, t); + res = provedByAnother(normProblem, t); if (TriggerUtils.isTrueOrFalse(res)) { - // addToCache(problem, res,cache); return res; } } return problem; } - // end + /** + * Normalises the literals of a clause reduced to a single literal, before it is assumed for the + * remaining clauses, so later decisions match it modulo the congruence. + * + * @param lits the literals to normalise + * @return the normalised literals, or {@code lits} unchanged when the congruence is trivial + */ + private ImmutableSet normalizeLiterals(ImmutableSet lits) { + if (congruence.isTrivial()) { + return lits; + } + ImmutableSet res = DefaultImmutableSet.nil(); + for (final JTerm l : lits) { + res = res.add(congruence.normalize(l)); + } + return res; + } - // cost computation - /** do two step refinement and return the cost */ + /** Returns the predicted cost by refining the clauses against the asserted literals. */ private long cost() { return firstRefine(); } /** - * refine every clause, by assume assertList are true and if a clause's cost is 0 which means it - * is refined to false, then cost 0 returned. If every clause's cost is -1 which means every - * clause is refined to true, cost -1 returned. Otherwise, multiply of every cost is return. - * Beside, if a clause is refined to a situation that only one literal is left, the literal will - * be add to assertLiterals. + * Refines every clause against the asserted literals and combines the results into a cost. A + * clause refined to false makes the whole instance cost 0. Clauses refined to true are dropped. + * The sizes of the remaining clauses are multiplied. A clause left with a single literal adds + * that literal to the asserted literals. When every clause is dropped and nothing was added the + * instance is trivially true and the cost is -1. */ private long firstRefine() { long cost = 1; @@ -220,7 +301,7 @@ private long firstRefine() { } if (c.literals.size() == 1) { assertChanged = true; - assertLiterals = assertLiterals.union(c.literals); + assertLiterals = assertLiterals.union(normalizeLiterals(c.literals)); } else { res.add(c); } @@ -236,23 +317,9 @@ private long firstRefine() { return cost; } - /** A sat() procedure with back searching */ - /* - * private long secondRefineX(SetOf assertLits, Map cache, Object[] cls, int index) { long - * cost = 1; for ( int i = index; i < cls.length; i++ ) { Clause c = (Clause)cls[i]; final - * SetOf ls = c.refine ( assertLits, cache ); if ( ls.contains ( falseT ) ) return 0; if ( - * ls.contains ( trueT ) ) return secondRefine ( assertLits, cache, cls, i + 1 ); final - * Iterator it = ls.iterator (); while ( it.hasNext () ) { SetOf nextLits = - * SetAsListOf.nil().union ( assertLits ); nextLits = nextLits.add ( it.next () ); final - * Map nextCache = new HashMap (); nextCache.putAll ( cache ); long nextCost = secondRefine ( - * nextLits, nextCache, cls, i + 1 ); cost = cost + nextCost; - * - * } } return cost; } - */ - private class Clause implements Iterable { - /** all literals contains in this clause */ + /** The literals of this clause. */ private ImmutableSet literals; public Clause(ImmutableSet lits) { @@ -264,9 +331,6 @@ public boolean equals(Object o) { if (!(o instanceof Clause other)) { return false; } - if (other.literals.size() != literals.size()) { - return false; - } return literals.equals(other.literals); } @@ -281,8 +345,8 @@ public Iterator iterator() { } /** - * @return 0 if this clause is refine to false. 1 if true. Otherwise,return the number of - * literals it left. + * @return 0 if this clause refined to false, -1 if it refined to true, otherwise the number + * of literals it still has */ public long cost() { if (literals.size() == 1 && literals.contains(falseT)) { @@ -294,21 +358,15 @@ public long cost() { return literals.size(); } - /** - * Refine this clause in two process, first try to refined by itself, @see selfRefine. - * Second refine this clause by assuming assertLiteras are true - */ + /** Refine this clause by assuming the asserted literals are true. */ public void firstRefine() { - // if (selfRefine(literals)) { - // literals = SetAsListOf.nil().add(trueT); - // return; - // } literals = this.refine(assertLiterals); } /** - * Refine literals in this clause, but it does not change literlas, only return literals - * that can't be removed by refining + * Returns the literals of this clause that refining against the asserted literals cannot + * remove. A single {@code trueT} means the clause is true, a single {@code falseT} means it + * is false. */ public ImmutableSet refine(Iterable assertLits) { ImmutableSet res = DefaultImmutableSet.nil(); @@ -329,36 +387,6 @@ public ImmutableSet refine(Iterable assertLits) { return res; } - /** - * This method is used for detect where a clause can be simply refined to to true. And it is - * implemented like this. Assume that the clause contains two literals Li and Lj. If - * (!Li->Lj) which is acturally (Li|Lj), is true, and the clasue is true. - * provedByAnthoer(Lj,!Li) is used to proved (!Li->Lj). Some examples are (!a|a) which is - * (!!a->a) and (a>=1|a<=0) which is !a>=1->a<=0 - */ - public boolean selfRefine(ImmutableSet lits) { - if (lits.size() <= 1) { - return false; - } - JTerm[] terms = lits.toArray(new JTerm[lits.size()]); - ImmutableSet next = lits.remove(terms[0]); - boolean opNot = terms[0].op() == Junctor.NOT; - JTerm axiom = opNot ? terms[0].sub(0) : tb.not(terms[0]); - for (int j = 1; j < terms.length; j++) { - JTerm pro = provedByAnother(terms[j], axiom); - final Operator op = pro.op(); - if (op == Junctor.TRUE) { - return true; - } - if (op == Junctor.FALSE - && terms[0].equalsModProperty(terms[j], IRRELEVANT_TERM_LABELS_PROPERTY)) { - next = next.remove(terms[j]); - literals = literals.remove(terms[j]); - } - } - return selfRefine(next); - } - @Override public String toString() { return literals.toString(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierInstantiationTieBreak.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierInstantiationTieBreak.java new file mode 100644 index 00000000000..e91785bf391 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierInstantiationTieBreak.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.quantifierHeuristics; + +import java.util.Collection; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.proof.Goal; + +import org.key_project.logic.Term; +import org.key_project.prover.sequent.Sequent; + +/** + * The within-band ordering of tied quantifier instantiation candidates. + * + * When several candidates share the predicted instantiation cost, the primary prediction cannot + * separate them, and the choice would otherwise fall to the position of the quantified formula on + * the sequent. A tie-break orders the band by content instead. Which content signal is used is a + * strategy: {@link PolarityTieBreak} orders by how strongly an instance is connected to the + * proving-polarity parts of the sequent, {@link GenPolTieBreak} orders by how late the instance's + * newest skolem constant was introduced on the branch, breaking a same-generation tie by the + * polarity connection. + * + * A strategy runs in two phases: {@link #prepare} computes the facts shared by all candidates of + * one quantified formula once and returns a {@link Scorer}; the scorer then answers each candidate. + * The tie-break value stays far below the distance of the scaled cost bands (see + * {@link de.uka.ilkd.key.strategy.quantifierHeuristics.InstantiationCostScalerFeature}), so the + * prediction itself is never overridden. + */ +interface QuantifierInstantiationTieBreak { + + /** + * The read-only view of a quantified formula's instantiation the tie-break reads: the candidate + * instances, the sequent they were collected from, the goal for the branch history, and access + * to the theory operators and caches. + * + * @param candidates the candidate instances + * @param sequent the sequent + * @param goal the goal + * @param services the services + */ + record View(Collection candidates, Sequent sequent, Goal goal, Services services) { + } + + /** + * Prepares the shared facts for the candidates of one quantified formula. + * + * @param view the instantiation view + * @return a scorer for the view's candidates + */ + Scorer prepare(View view); + + /** Scores a single candidate, using the facts prepared for its quantified formula. */ + @FunctionalInterface + interface Scorer { + /** + * @param instance a candidate instance + * @return its tie-break cost, small compared to the scaled cost bands + */ + long tieBreak(Term instance); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierTheorySupport.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierTheorySupport.java new file mode 100644 index 00000000000..3c9a2ebe71b --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/QuantifierTheorySupport.java @@ -0,0 +1,131 @@ +/* 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.quantifierHeuristics; + +import java.util.List; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.op.Junctor; + +import org.key_project.logic.op.QuantifiableVariable; +import org.key_project.util.collection.ImmutableSet; + +/** + * A theory's contribution to quantifier instantiation. + * + * The instantiation heuristic needs knowledge that is specific to each theory at two points. When + * choosing triggers: what counts as coordinate or connective material rather than a meaningful + * observation (an array index, an integer comparison), and which derived triggers make an + * observation matchable against the terms a proof actually produces (a read generalized over the + * heaps of a symbolic execution). And when predicting the cost of an instantiation: whether a + * literal is proved true or false, from itself or from an assumed literal, by the theory's own + * reasoning (arithmetic comparisons, equality up to renaming). This interface isolates that + * knowledge. Registering a new support in {@link TriggersSet#THEORY_SUPPORTS} is the only change + * needed to teach the heuristic about a further theory; {@link TriggersSet} and + * {@link PredictCostProver} stay untouched. + */ +interface QuantifierTheorySupport { + + /** The outcome of judging a literal for cost prediction. */ + enum LiteralDecision { + PROVED, REFUTED, UNKNOWN; + + /** + * @return the decision for the negation of the judged literal + */ + LiteralDecision negate() { + return switch (this) { + case PROVED -> REFUTED; + case REFUTED -> PROVED; + case UNKNOWN -> UNKNOWN; + }; + } + } + + /** + * Maps a truth term, as the theory reasoning returns it, to a decision: the true constant is + * {@link LiteralDecision#PROVED}, the false constant {@link LiteralDecision#REFUTED}, and any + * other term (an undecided literal) {@link LiteralDecision#UNKNOWN}. + * + * @param t a truth term + * @return the matching decision + */ + static LiteralDecision fromTruthTerm(JTerm t) { + if (t.op() == Junctor.TRUE) { + return LiteralDecision.PROVED; + } + if (t.op() == Junctor.FALSE) { + return LiteralDecision.REFUTED; + } + return LiteralDecision.UNKNOWN; + } + + /** + * Whether {@code candidate} must not be used as a standalone trigger, because for this theory + * it is coordinate or connective material rather than a meaningful observation. + * + * @param candidate a subterm that contains the quantified variables and is a trigger candidate + * @param services access to the theory operators + */ + boolean rejectsAsTrigger(JTerm candidate, Services services); + + /** + * Additional triggers derived from the accepted trigger {@code term}, for example a read + * generalized so it matches across the many heaps of a proof. The returned triggers are matched + * by unification (they may contain metavariables). + * + * @param term an accepted trigger term + * @param clauseVariables the quantified variables of the clause the trigger belongs to + * @param services access to the theory operators + * @return derived triggers, possibly empty + */ + List provideTriggers(JTerm term, + ImmutableSet clauseVariables, Services services); + + /** + * Checks whether the literal holds on its own, for cost prediction. The literal is passed + * already stripped of its leading negations; the caller re-applies them to the returned + * decision, so an implementation reasons about the positive form only. + * + * @param strippedLiteral a literal without leading negations + * @param services access to the theory operators + * @return whether this theory proves the literal true, false, or cannot decide it + */ + default LiteralDecision decideStrippedSelf(JTerm strippedLiteral, Services services) { + return LiteralDecision.UNKNOWN; + } + + /** + * Checks whether the literal follows from an assumed-true {@code axiom}, for cost prediction. + * Leading negations of both the literal and the axiom are handled by the implementation. + * + * @param literal a literal to decide + * @param axiom a literal assumed to be true + * @param services access to the theory operators + * @return whether the axiom proves the literal true, false, or cannot decide it + */ + default LiteralDecision decideFromAxiom(JTerm literal, JTerm axiom, Services services) { + return LiteralDecision.UNKNOWN; + } + + /** + * Whether the equality-based normalisation of the cost prediction (see {@link Congruence}) may + * rewrite occurrences of {@code from} to {@code to}, justified by an assumed equality between + * the two. The proof search keeps the terms of a theory in a normal form of the theory's own + * rules, integer terms in polynomial form for example. A theory vetoes here when the rewrite + * would replace such a normal form, so the decisions of {@link #decideStrippedSelf} and + * {@link #decideFromAxiom} still see the forms they understand. When a rewrite is vetoed the + * congruence tries the opposite direction, and leaves the equality out entirely if that is + * vetoed too. + * + * @param from the term whose occurrences would be rewritten + * @param to the replacement term + * @param services access to the theory operators + * @return whether this theory permits the rewrite + */ + default boolean allowsEqualityRewrite(JTerm from, JTerm to, Services services) { + return true; + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java index 04ff46ba804..f354965ddb4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java @@ -3,15 +3,14 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy.quantifierHeuristics; -import java.util.Iterator; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import de.uka.ilkd.key.java.Services; -import de.uka.ilkd.key.java.transformations.pipeline.PipelineConstants; -import de.uka.ilkd.key.ldt.IntegerLDT; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.TermServices; import de.uka.ilkd.key.logic.label.TermLabelManager; @@ -21,6 +20,7 @@ import org.key_project.logic.op.QuantifiableVariable; import org.key_project.util.collection.DefaultImmutableSet; import org.key_project.util.collection.ImmutableArray; +import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSet; /** @@ -29,10 +29,30 @@ */ public class TriggersSet { + /** + * Per-theory support consulted for rejecting unsuitable trigger material, providing derived + * triggers, and (from {@link PredictCostProver}) deciding literals during cost prediction. + * Support for a further theory is added by extending this list. The order is significant for + * cost prediction: literals are decided by the first support that reaches a verdict, so + * equality + * is consulted before integer arithmetic, matching the original prover. + */ + static final java.util.List THEORY_SUPPORTS = + java.util.List.of(new HeapArrayTheorySupport(), new EqualityTheorySupport(), + new IntegerTheorySupport()); + /** Quantified formula of PCNF */ private final JTerm allTerm; - /** all Triggers for allTerm */ - private ImmutableSet allTriggers = DefaultImmutableSet.nil(); + /** + * The triggers collected while this set is built. A hash set answers the duplicate check in + * constant time, whereas {@link ImmutableSet#add} scans the elements it already holds, which + * costs quadratic time in the number of triggers a clause yields. Collection order is kept so + * {@link #getAllTriggers()} can hand out exactly the set repeated adds would have produced. + */ + private final LinkedHashSet collectedTriggers = new LinkedHashSet<>(); + + /** Built from {@link #collectedTriggers} on first request. */ + private ImmutableSet allTriggers; /** * a HashMap from Term to Trigger which stores different * subterms of allTerm with its according trigger @@ -117,10 +137,11 @@ private void initTriggers(Services services) { */ private Trigger createUniTrigger(JTerm trigger, ImmutableSet universalVariables, boolean isUnify, - boolean isElement) { + boolean isElement, boolean matchByUnification) { Trigger cached = termToTrigger.get(trigger); if (cached == null) { - cached = new UniTrigger(trigger, universalVariables, isUnify, isElement, this); + cached = new UniTrigger(trigger, universalVariables, isUnify, isElement, + matchByUnification, this); termToTrigger.put(trigger, cached); } return cached; @@ -185,7 +206,7 @@ public void createTriggers(Services services) { addMaximalUniTriggers(positive, services); } } - buildCoveringMultiTriggers(elementsOfMultiTrigger.iterator()); + buildCoveringMultiTriggers(); } /** @@ -211,9 +232,11 @@ private boolean addMaximalUniTriggers(JTerm term, Services services) { } } + // a term becomes a trigger only if none of its subterms yielded one; a subterm + // whose candidates were all rejected (not acceptable as triggers) does not count, + // so the next enclosing meaningful term gets its chance if (!foundSubtriggers) { - addUniTrigger(term, services); - return true; + return addUniTrigger(term, services); } return true; @@ -282,87 +305,149 @@ private boolean mightContainTriggers(JTerm term) { } /** - * Further criteria for triggers. This is just a HACK, there should be a more general - * framework for characterising acceptable triggers + * A trigger candidate is acceptable unless some theory's {@link QuantifierTheorySupport} + * rejects it as coordinate or connective material. */ private boolean isAcceptableTrigger(JTerm term, Services services) { - final Operator op = term.op(); - - // we do not want to match on expressions a.$created - - if (term.op() == services.getTypeConverter().getHeapLDT().getSelect(term.sort(), - services)) { - if (term.sub(2).op().name().toString() - .endsWith(PipelineConstants.IMPLICIT_CREATED)) { + for (final QuantifierTheorySupport support : THEORY_SUPPORTS) { + if (support.rejectsAsTrigger(term, services)) { return false; } } - - final IntegerLDT integerLDT = services.getTypeConverter().getIntegerLDT(); - // matching on equations and inequalities does not seem to have any - // positive effect for the time being - return op != Equality.EQUALS && op != integerLDT.getLessOrEquals() - && op != integerLDT.getGreaterOrEquals(); - - /* - * if ( op == Op.EQUALS ) { // we do not want to match on equations t = null if ( - * term.sub ( 0 ).sort () == Sort.NULL || term.sub ( 1 ).sort () == Sort.NULL ) return - * false; // we do not want to match on equations t = TRUE if ( "TRUE".equals ( term.sub - * ( 0 ).op ().name ().toString () ) || "TRUE".equals ( term.sub ( 1 ).op ().name - * ().toString () ) ) return false; } - */ + return true; } /** - * add a uni-trigger to triggers set or add an element of multi-triggers for this clause + * add a uni-trigger to triggers set or add an element of multi-triggers for this clause, + * together with the derived triggers each theory's {@link QuantifierTheorySupport} provides + * + * @return whether a trigger was registered for {@code term} */ - private void addUniTrigger(JTerm term, Services services) { + private boolean addUniTrigger(JTerm term, Services services) { if (!isAcceptableTrigger(term, services)) { - return; + return false; + } + registerUniTrigger(term, false); + // A theory's generalisation is a different term, not a weaker one: it can match where + // the original does not and fail to match where the original does. Both are therefore + // registered, so an instantiation reachable through either one stays reachable. + for (final QuantifierTheorySupport support : THEORY_SUPPORTS) { + for (final JTerm derived : support.provideTriggers(term, clauseVariables, + services)) { + registerUniTrigger(derived, true); + } } + return true; + } + + private void registerUniTrigger(JTerm term, boolean matchByUnification) { final boolean isUnify = !term.freeVars().subset(clauseVariables); final boolean isElement = !clauseVariables.subset(term.freeVars()); final ImmutableSet uniVarsInTerm = TriggerUtils.intersect(term.freeVars(), clauseVariables); - Trigger trigger = createUniTrigger(term, uniVarsInTerm, isUnify, isElement); + Trigger trigger = + createUniTrigger(term, uniVarsInTerm, isUnify, isElement, matchByUnification); if (isElement) { elementsOfMultiTrigger = elementsOfMultiTrigger.add(trigger); } else { - allTriggers = allTriggers.add(trigger); + collectedTriggers.add(trigger); } } /** - * Enumerate combinations of the multi-trigger elements and register each combination that - * covers all clause variables as a multi-trigger (via {@link #tryAddCoveringMultiTrigger}). - * A covering combination is not extended further, so only minimal covering sets are kept. + * Registers a multi-trigger for every minimal set of elements that together cover the + * clause's universal variables. * - * @param remainingElements the elements still to be combined - * @return the non-covering partial combinations (used internally for the recursion) + * A covering set is minimal when each member contributes a variable the other members do + * not, so a minimal cover never has more members than the clause has variables. The search + * looks for such covers directly: it takes a variable that is still uncovered, tries each + * element covering it, and abandons a branch as soon as a member is left contributing + * nothing (see {@link #keepOwnedVariables}). Building all combinations of the elements + * instead and keeping the covering ones yields the same instantiations, but visits 2^n + * combinations, which is out of reach once a clause offers a few dozen elements. */ - private Set> buildCoveringMultiTriggers( - Iterator remainingElements) { - Set> partialCombinations = new LinkedHashSet<>(); - if (remainingElements.hasNext()) { - final Trigger element = remainingElements.next(); - ImmutableSet singleton = DefaultImmutableSet.nil().add(element); - partialCombinations.add(singleton); - Set> tailCombinations = - buildCoveringMultiTriggers(remainingElements); - - partialCombinations.addAll(tailCombinations); - for (ImmutableSet tailCombination : tailCombinations) { - ImmutableSet combination = tailCombination.add(element); - // A covering combination becomes a multi-trigger and is not extended further; - // its supersets would be redundant. - if (tryAddCoveringMultiTrigger(combination)) { - continue; - } - partialCombinations.add(combination); + private void buildCoveringMultiTriggers() { + final List elements = new ArrayList<>(); + final List> coveredBy = new ArrayList<>(); + for (final Trigger element : elementsOfMultiTrigger) { + elements.add(element); + coveredBy.add(TriggerUtils + .intersect(((JTerm) element.getTriggerTerm()).freeVars(), clauseVariables)); + } + coverRemainingVariables(clauseVariables, DefaultImmutableSet.nil(), new ArrayList<>(), + elements, coveredBy); + } + + /** + * Extends {@code chosen} until it covers the clause variables, registering every complete + * cover as a multi-trigger. + * + * @param uncovered the clause variables that no member of {@code chosen} covers yet + * @param chosen the elements picked so far + * @param ownedVariables for each element in {@code chosen}, the clause variables that + * element alone covers + * @param elements the multi-trigger elements of the clause + * @param coveredBy for each element, the clause variables that element covers + */ + private void coverRemainingVariables(ImmutableSet uncovered, + ImmutableSet chosen, + List> ownedVariables, List elements, + List> coveredBy) { + if (uncovered.isEmpty()) { + tryAddCoveringMultiTrigger(chosen); + return; + } + // Resolve one fixed variable per step: every member is then justified by the variable + // it was picked for, so no branch grows a set that already covers the clause. + final QuantifiableVariable target = uncovered.iterator().next(); + for (int i = 0, sz = elements.size(); i < sz; i++) { + final Trigger element = elements.get(i); + final ImmutableSet covers = coveredBy.get(i); + if (!covers.contains(target) || chosen.contains(element)) { + continue; + } + final List> owned = + new ArrayList<>(ownedVariables.size() + 1); + if (!keepOwnedVariables(ownedVariables, covers, owned)) { + continue; } + ImmutableSet remaining = uncovered; + for (final QuantifiableVariable covered : covers) { + remaining = remaining.remove(covered); + } + owned.add(TriggerUtils.intersect(covers, uncovered)); + coverRemainingVariables(remaining, chosen.add(element), owned, elements, coveredBy); } - return partialCombinations; + } + + /** + * Takes the variables a newly picked element covers away from the elements picked before + * it. An element that is left owning nothing covers only variables the others already + * cover, so the cover under construction would still cover the clause without it. Such a + * cover is never built: a multi-trigger fires only when all of its elements match, so the + * cover without the element fires whenever the one with it does, and yields the same + * instantiations from fewer matches. + * + * @param ownedVariables for each element picked so far, the variables it alone covers + * @param covers the clause variables the newly picked element covers + * @param owned receives the reduced ownership of the elements picked so far + * @return whether every element picked so far still owns a variable + */ + private boolean keepOwnedVariables(List> ownedVariables, + ImmutableSet covers, + List> owned) { + for (final ImmutableSet ownedByEarlier : ownedVariables) { + ImmutableSet left = ownedByEarlier; + for (final QuantifiableVariable covered : covers) { + left = left.remove(covered); + } + if (left.isEmpty()) { + return false; + } + owned.add(left); + } + return true; } /** @@ -380,7 +465,7 @@ private boolean tryAddCoveringMultiTrigger(ImmutableSet combination) { } if (clauseVariables.subset(coveredVariables)) { Trigger multiTrigger = createMultiTrigger(combination, clause, clauseVariables); - allTriggers = allTriggers.add(multiTrigger); + collectedTriggers.add(multiTrigger); return true; } return false; @@ -392,6 +477,13 @@ public JTerm getQuantifiedFormula() { } public ImmutableSet getAllTriggers() { + if (allTriggers == null) { + // Adding to an immutable set prepends, so building it by repeated adds leaves the + // triggers in the reverse of the order they were collected. Reverse here as well, so + // the trigger order the strategy sees does not depend on how the set was assembled. + allTriggers = DefaultImmutableSet + .fromImmutableList(ImmutableList.fromList(collectedTriggers).reverse()); + } return allTriggers; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TwoSidedMatching.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TwoSidedMatching.java index 7c3eddb8c56..810ae65810f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TwoSidedMatching.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TwoSidedMatching.java @@ -16,13 +16,11 @@ import org.key_project.util.collection.ImmutableSet; /** - * Matching triggers within another quantifier expression. Problems with the current implementation: - *

- * * the usage of EqualityConstraint for unification implies that a variable is never instantiated - * with non-rigid terms - *

- * * it is unclear whether certain instantiations are lost due to too strict type checks in - * EqualityConstraint + * Matching triggers within another quantifier expression. The unification through + * EqualityConstraint binds a metavariable to ground non-rigid terms as well: the metavariable + * stands for a quantifier instance, and soundness rests on the wary substitution applied when + * the taclet is applied, not on the matching. A known limitation: it is unclear whether certain + * instantiations are lost due to too strict type checks in EqualityConstraint. */ class TwoSidedMatching { diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/UniTrigger.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/UniTrigger.java index d5ab40f7774..765883d6510 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/UniTrigger.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/UniTrigger.java @@ -34,6 +34,12 @@ class UniTrigger implements Trigger { * only be matched by (two-sided) unification, not by basic matching. */ private final boolean onlyUnify; + /** + * If {@code true} the trigger contains a metavariable in place of a ground subterm (a + * heap-generalized array read) and is matched by unification even against ground terms, so the + * metavariable can bind to any heap. Plain triggers use syntactic matching on ground terms. + */ + private final boolean matchByUnification; private final boolean isElementOfMultitrigger; // A TriggersSet is cached per proof (ServiceCaches.triggerSetCache) and thus shared across the @@ -41,19 +47,20 @@ class UniTrigger implements Trigger { // exact ConcurrentLruCache is used (not the striped one): the cached substitutions are // expensive // to recompute, so the better hit rate of exact LRU eviction outweighs the trivial contention - // on - // get/put. The get-then-put below stays non-atomic on purpose (the expensive matching runs - // outside the lock); at worst two workers redundantly compute the same (pure) result. + // on get/put. The get-then-put below stays non-atomic on purpose (the expensive matching + // run outside the lock); at worst two workers redundantly compute the same (pure) result. private final ConcurrentLruCache> matchResults = new ConcurrentLruCache<>(1000); UniTrigger(Term trigger, ImmutableSet universalVariables, boolean onlyUnify, - boolean isElementOfMultitrigger, TriggersSet owningTriggerSet) { + boolean isElementOfMultitrigger, boolean matchByUnification, + TriggersSet owningTriggerSet) { this.trigger = trigger; this.universalVariables = universalVariables; this.onlyUnify = onlyUnify; this.isElementOfMultitrigger = isElementOfMultitrigger; + this.matchByUnification = matchByUnification; this.owningTriggerSet = owningTriggerSet; } @@ -78,7 +85,8 @@ private ImmutableSet cachedSubstitutionsForTerm(Term target, Servi private ImmutableSet computeSubstitutionsForTerm(Term target, Services services) { ImmutableSet subs = DefaultImmutableSet.nil(); - if (target.freeVars().size() > 0 || target.op() instanceof Quantifier) { + if (target.freeVars().size() > 0 || target.op() instanceof Quantifier + || matchByUnification) { subs = Matching.twoSidedMatching(this, target, services); } else if (!onlyUnify) { subs = Matching.basicMatching(this, target); @@ -148,8 +156,7 @@ private static boolean containsCycle(Substitution substitution) { /** * Worklist reachability check (originally adapted from EqualityConstraint): starting from the * term bound to {@code var}, follow variable bindings transitively and report whether - * {@code var} - * is reached again -- i.e. whether its definition is cyclic. + * {@code var} is reached again -- i.e. whether its definition is cyclic. */ private static boolean reachesItself( ImmutableMap varMap, diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/TriggeredInstantiations.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/TriggeredInstantiations.java index 4f812bc7680..d491fc665c6 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/TriggeredInstantiations.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/termgenerator/TriggeredInstantiations.java @@ -170,14 +170,11 @@ private void collectAxiomsAndCandidateTerms(final Set terms, final Set axioms, - Services services) { - + private boolean isAvoidConditionProvable(JTerm cond, + PredictCostProver.PreparedAxioms axioms, Services services) { long cost = PredictCostProver.computerInstanceCost( new Substitution(DefaultImmutableMap.nilMap()), cond, axioms, services); - - return cost == -1; } @@ -189,6 +186,10 @@ private HashSet computeInstances(Services services, final HashSet instances = new HashSet<>(); final HashSet alreadyChecked = new HashSet<>(); + // The axioms are fixed for the sequent, so the congruence and the normalization are + // built once here instead of once per avoid condition per candidate. + final PredictCostProver.PreparedAxioms prepared = + PredictCostProver.prepare(axioms, services); for (final JTerm t : terms) { boolean addToInstances = true; @@ -201,7 +202,7 @@ private HashSet computeInstances(Services services, ImmutableList conditions = instantiateConditions(services, app, middle); for (JTerm condition : conditions) { - if (isAvoidConditionProvable(condition, axioms, services)) { + if (isAvoidConditionProvable(condition, prepared, services)) { addToInstances = false; break; } diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/CongruenceTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/CongruenceTest.java new file mode 100644 index 00000000000..2ae30a0fc74 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/CongruenceTest.java @@ -0,0 +1,122 @@ +/* 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.quantifierHeuristics; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.op.LogicVariable; +import de.uka.ilkd.key.logic.sort.SortImpl; +import de.uka.ilkd.key.rule.TacletForTests; + +import org.key_project.logic.Name; +import org.key_project.logic.op.Function; +import org.key_project.logic.sort.Sort; +import org.key_project.util.collection.DefaultImmutableSet; +import org.key_project.util.collection.ImmutableSet; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Checks {@link Congruence}: an assumed equality rewrites occurrences of its left side to its + * right side, the direction flips when the sequent's orientation would widen the sort, number + * literals end up as the representative of their class, and terms binding variables are left + * untouched. These are the properties the prediction relies on when it normalizes literals + * before deciding them. + */ +public class CongruenceTest { + + private static final Services SERVICES = TacletForTests.services(); + private static final TermBuilder TB = SERVICES.getTermBuilder(); + + private static ImmutableSet literals(JTerm... lits) { + ImmutableSet set = DefaultImmutableSet.nil(); + for (final JTerm lit : lits) { + set = set.add(lit); + } + return set; + } + + @Test + void rewritesAlongTheSequentOrientation() { + final Sort s = new SortImpl(new Name("congS")); + final Function a = new JFunction(new Name("congA"), s); + final Function b = new JFunction(new Name("congB"), s); + final Function f = new JFunction(new Name("congF"), s, s); + final JTerm ta = TB.func(a); + final JTerm tb = TB.func(b); + + final Congruence c = new Congruence(literals(TB.equals(ta, tb)), SERVICES); + assertFalse(c.isTrivial()); + assertEquals(tb, c.normalize(ta), "the left side rewrites to the right side"); + assertEquals(TB.func(f, tb), c.normalize(TB.func(f, ta)), + "occurrences below an operator rewrite as well"); + assertEquals(tb, c.normalize(tb), "the representative stays itself"); + } + + @Test + void wideningDirectionIsFlipped() { + final Sort wide = new SortImpl(new Name("congWide")); + final Sort narrow = new SortImpl(new Name("congNarrow"), wide); + final Function o = new JFunction(new Name("congO"), wide); + final Function d = new JFunction(new Name("congD"), narrow); + final JTerm to = TB.func(o); + final JTerm td = TB.func(d); + + // Written with the narrow term on the left: reading it left to right would put the + // wide-sorted term into positions requiring the narrow sort, so the direction flips. + final Congruence c = new Congruence(literals(TB.equals(td, to)), SERVICES); + assertEquals(td, c.normalize(to), + "the wide term rewrites to the narrow one, not the other way around"); + assertEquals(td, c.normalize(td)); + + // Written with the wide term on the left, the sequent orientation is already narrowing. + final Congruence c2 = new Congruence(literals(TB.equals(to, td)), SERVICES); + assertEquals(td, c2.normalize(to)); + } + + @Test + void numberLiteralsBecomeTheRepresentative() { + final Sort intSort = SERVICES.getTypeConverter().getIntegerLDT().targetSort(); + final Function a = new JFunction(new Name("congIntA"), intSort); + final JTerm ta = TB.func(a); + final JTerm five = TB.zTerm(5); + + final Congruence left = new Congruence(literals(TB.equals(ta, five)), SERVICES); + assertEquals(five, left.normalize(ta), "a = 5 rewrites a to 5"); + final Congruence right = new Congruence(literals(TB.equals(five, ta)), SERVICES); + assertEquals(five, right.normalize(ta), + "5 = a also rewrites a to 5: the theory refuses a literal that rewrites away"); + } + + @Test + void termsBindingVariablesAreLeftUntouched() { + final Sort s = new SortImpl(new Name("congBindS")); + final Function a = new JFunction(new Name("congBindA"), s); + final Function b = new JFunction(new Name("congBindB"), s); + final Function p = + new JFunction(new Name("congBindP"), de.uka.ilkd.key.ldt.JavaDLTheory.FORMULA, s); + final LogicVariable x = new LogicVariable(new Name("congBindX"), s); + + final Congruence c = + new Congruence(literals(TB.equals(TB.func(a), TB.func(b))), SERVICES); + final JTerm quantified = TB.all(x, TB.func(p, TB.func(a))); + assertSame(quantified, c.normalize(quantified), + "a term binding variables is returned as it is"); + } + + @Test + void trivialWithoutEqualities() { + final Congruence c = new Congruence(DefaultImmutableSet.nil(), SERVICES); + assertTrue(c.isTrivial()); + final JTerm t = TB.tt(); + assertSame(t, c.normalize(t), "the trivial congruence is the identity"); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArithTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArithTest.java new file mode 100644 index 00000000000..79315d794bb --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HandleArithTest.java @@ -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 */ +package de.uka.ilkd.key.strategy.quantifierHeuristics; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.op.Junctor; +import de.uka.ilkd.key.rule.TacletForTests; + +import org.key_project.logic.Name; +import org.key_project.logic.op.Function; +import org.key_project.logic.sort.Sort; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests for the arithmetic reasoning used to judge quantifier instantiations + * ({@link HandleArith}). The quantifier heuristic scores an instantiation as useless when the + * instantiated formula is trivially true given the assumptions; deciding that relies on being + * able to prove one integer comparison from another. These tests pin that reasoning. + */ +public class HandleArithTest { + + private Services services; + private TermBuilder tb; + /** an integer constant standing for a skolem index like {@code j_3}. */ + private JTerm c; + + @BeforeEach + public void setUp() { + services = TacletForTests.services(); + tb = services.getTermBuilder(); + final Sort intSort = services.getTypeConverter().getIntegerLDT().targetSort(); + final Function cf = new JFunction(new Name("c_idx"), intSort); + c = tb.func(cf); + } + + /** Whether {@link HandleArith#provedByArith} proves {@code problem} from {@code axiom}. */ + private boolean provesTrue(JTerm problem, JTerm axiom) { + return HandleArith.provedByArith(problem, axiom, services).op() == Junctor.TRUE; + } + + /** Whether {@code problem} is refuted (its negation proved) from {@code axiom}. */ + private boolean provesFalse(JTerm problem, JTerm axiom) { + return HandleArith.provedByArith(problem, axiom, services).op() == Junctor.FALSE; + } + + @Test + public void deduceLessThanZeroFromAtMostMinusOne() { + // c <= -1 entails c < 0 (over the integers c < 0 is c <= -1) + assertEquals(true, provesTrue(tb.lt(c, tb.zero()), tb.leq(c, tb.zTerm(-1)))); + } + + @Test + public void deduceAtMostMinusOneFromLessThanZero() { + // c < 0 entails c <= -1 (the strict-assumption direction) + assertEquals(true, provesTrue(tb.leq(c, tb.zTerm(-1)), tb.lt(c, tb.zero()))); + } + + @Test + public void anAxiomProvesItself() { + // the range literal is literally an assumption + assertEquals(true, provesTrue(tb.leq(c, tb.zTerm(-1)), tb.leq(c, tb.zTerm(-1)))); + } + + @Test + public void weakerUpperBoundFollows() { + // c <= -1 entails c <= 5 + assertEquals(true, provesTrue(tb.leq(c, tb.zTerm(5)), tb.leq(c, tb.zTerm(-1)))); + } + + @Test + public void strongerLowerBoundEntailsWeakerOne() { + // c <= -2 entails c <= -1 + assertEquals(true, provesTrue(tb.leq(c, tb.zTerm(-1)), tb.leq(c, tb.zTerm(-2)))); + } + + @Test + public void contradictoryLowerBoundIsRefuted() { + // c <= -1 makes c >= 0 false + assertEquals(true, provesFalse(tb.geq(c, tb.zero()), tb.leq(c, tb.zTerm(-1)))); + } + + @Test + public void unrelatedBoundProvesNothing() { + // c <= 5 neither proves nor refutes c <= -1 + final JTerm r = HandleArith.provedByArith(tb.leq(c, tb.zTerm(-1)), tb.leq(c, tb.zTerm(5)), + services); + assertEquals(false, r.op() == Junctor.TRUE || r.op() == Junctor.FALSE); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityWalkTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityWalkTest.java new file mode 100644 index 00000000000..6ae08b91638 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PolarityWalkTest.java @@ -0,0 +1,129 @@ +/* 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.quantifierHeuristics; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.op.LogicVariable; +import de.uka.ilkd.key.logic.sort.SortImpl; +import de.uka.ilkd.key.rule.TacletForTests; +import de.uka.ilkd.key.strategy.quantifierHeuristics.PolarityOccurrenceTieBreak.OccInfo; + +import org.key_project.logic.Name; +import org.key_project.logic.op.Function; +import org.key_project.logic.sort.Sort; +import org.key_project.prover.sequent.SequentFormula; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Checks the polarity walk behind the occurrence tie-break: which operators of a sequent formula + * are recorded at proving polarity {@code +1} respectively {@code -1}, relative to the formula + * root. Negation and the left of an implication flip, conjunction, disjunction and the right of + * an implication keep, quantifiers and equivalences are neutral, the condition of a conditional + * is neutral while its branches keep, and below an atom the polarity is frozen for the atom's + * whole subtree. + */ +public class PolarityWalkTest { + + private static final Services SERVICES = TacletForTests.services(); + private static final TermBuilder TB = SERVICES.getTermBuilder(); + + private static final Sort S = new SortImpl(new Name("polS")); + private static final Function A = new JFunction(new Name("polA"), S); + private static final Function G = new JFunction(new Name("polG"), S, S); + private static final Function P = pred("polP"); + private static final Function Q = pred("polQ"); + + private static JFunction pred(String name) { + return new JFunction(new Name(name), de.uka.ilkd.key.ldt.JavaDLTheory.FORMULA, S); + } + + private static JTerm p() { + return TB.func(P, TB.func(G, TB.func(A))); + } + + private static JTerm q() { + return TB.func(Q, TB.func(A)); + } + + private static OccInfo walk(JTerm formula) { + return PolarityOccurrenceTieBreak.occInfo(new SequentFormula(formula), SERVICES); + } + + private static void assertPlus(OccInfo info, Function op) { + assertTrue(info.opsRelPlus().contains(op), op + " must be at proving polarity +1"); + assertFalse(info.opsRelMinus().contains(op), op + " must not also be at -1"); + } + + private static void assertMinus(OccInfo info, Function op) { + assertTrue(info.opsRelMinus().contains(op), op + " must be at proving polarity -1"); + assertFalse(info.opsRelPlus().contains(op), op + " must not also be at +1"); + } + + private static void assertNeutral(OccInfo info, Function op) { + assertTrue(info.opsAny().contains(op), op + " must be seen by the walk"); + assertFalse(info.opsRelPlus().contains(op) || info.opsRelMinus().contains(op), + op + " must be at neutral polarity"); + } + + @Test + void conjunctionAndDisjunctionKeepThePolarity() { + final OccInfo and = walk(TB.and(p(), q())); + assertPlus(and, P); + assertPlus(and, Q); + final OccInfo or = walk(TB.or(p(), q())); + assertPlus(or, P); + assertPlus(or, Q); + } + + @Test + void negationFlipsThePolarity() { + final OccInfo info = walk(TB.not(p())); + assertMinus(info, P); + final OccInfo doubled = walk(TB.not(TB.not(p()))); + assertPlus(doubled, P); + } + + @Test + void implicationFlipsOnlyItsLeft() { + final OccInfo info = walk(TB.imp(p(), q())); + assertMinus(info, P); + assertPlus(info, Q); + } + + @Test + void quantifierAndEquivalenceAreNeutral() { + final LogicVariable x = new LogicVariable(new Name("polX"), S); + final OccInfo all = walk(TB.all(x, TB.func(P, TB.var(x)))); + assertNeutral(all, P); + final OccInfo eqv = walk( + SERVICES.getTermFactory().createTerm( + de.uka.ilkd.key.logic.op.Equality.EQV, p(), q())); + assertNeutral(eqv, P); + assertNeutral(eqv, Q); + } + + @Test + void conditionIsNeutralWhileBranchesKeep() { + final OccInfo info = walk(TB.ife(p(), q(), q())); + assertNeutral(info, P); + assertPlus(info, Q); + } + + @Test + void polarityIsFrozenBelowAnAtom() { + // P itself is the atom of the formula !P(g(a)): the atom is at -1, and so is its whole + // subtree, the function g and the constant a included. + final OccInfo info = walk(TB.not(p())); + assertMinus(info, P); + assertMinus(info, G); + assertMinus(info, A); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProverTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProverTest.java new file mode 100644 index 00000000000..640506fc820 --- /dev/null +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/PredictCostProverTest.java @@ -0,0 +1,117 @@ +/* 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.quantifierHeuristics; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.ldt.JavaDLTheory; +import de.uka.ilkd.key.logic.JTerm; +import de.uka.ilkd.key.logic.TermBuilder; +import de.uka.ilkd.key.logic.op.JFunction; +import de.uka.ilkd.key.logic.op.LogicVariable; +import de.uka.ilkd.key.rule.TacletForTests; + +import org.key_project.logic.Name; +import org.key_project.logic.Term; +import org.key_project.logic.op.Function; +import org.key_project.logic.op.QuantifiableVariable; +import org.key_project.logic.sort.Sort; +import org.key_project.util.collection.DefaultImmutableMap; +import org.key_project.util.collection.DefaultImmutableSet; +import org.key_project.util.collection.ImmutableMap; +import org.key_project.util.collection.ImmutableSet; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +/** + * Tests for the cost the quantifier heuristic assigns to a candidate instantiation + * ({@link PredictCostProver#computerInstanceCost}). A cost of {@code -1} means the instantiated + * formula is trivially true under the assumptions, so the instantiation is useless and is + * dropped by the callers. + * + *

+ * The formula modelled here is an array range invariant of the shape occurring in removeDup: + * {@code x <= -1 | x >= n | p(x)} (index out of range below, out of range above, or the element + * property holds). Instantiating it with an index known to be out of range makes a range + * disjunct true, so the instance is useless and its cost must be {@code -1}. + */ +public class PredictCostProverTest { + + private Services services; + private TermBuilder tb; + private LogicVariable x; // the quantified index + private JTerm c; // the concrete index to instantiate with (a skolem like j_3) + private JTerm n; // the upper range bound + private Function p; // the element property p(int) : Formula + + @BeforeEach + public void setUp() { + services = TacletForTests.services(); + tb = services.getTermBuilder(); + final Sort intSort = services.getTypeConverter().getIntegerLDT().targetSort(); + x = new LogicVariable(new Name("x"), intSort); + c = tb.func(new JFunction(new Name("c_idx"), intSort)); + n = tb.func(new JFunction(new Name("n_bound"), intSort)); + p = new JFunction(new Name("p_prop"), JavaDLTheory.FORMULA, intSort); + } + + /** The invariant body {@code x <= -1 | x >= n | p(x)}. */ + private JTerm matrix() { + return tb.or(tb.leq(tb.var(x), tb.zTerm(-1)), + tb.or(tb.geq(tb.var(x), n), tb.func(p, tb.var(x)))); + } + + /** The substitution {@code x := c}. */ + private Substitution instantiateWithC() { + ImmutableMap map = DefaultImmutableMap.nilMap(); + map = map.put(x, c); + return new Substitution(map); + } + + private ImmutableSet assumptions(JTerm... literals) { + ImmutableSet set = DefaultImmutableSet.nil(); + for (JTerm literal : literals) { + set = set.add(literal); + } + return set; + } + + private long cost(ImmutableSet assumptions) { + return PredictCostProver.computerInstanceCost(instantiateWithC(), matrix(), assumptions, + services); + } + + @Test + public void uselessWhenLowerBoundKnownDirectly() { + // c <= -1 is assumed, so the first disjunct is true and the instance is useless + assertEquals(-1, cost(assumptions(tb.leq(c, tb.zTerm(-1))))); + } + + @Test + public void uselessWhenStrongerLowerBoundKnown() { + // c <= -2 entails c <= -1, so the first disjunct is still provably true + assertEquals(-1, cost(assumptions(tb.leq(c, tb.zTerm(-2))))); + } + + @Test + public void uselessWhenUpperBoundKnown() { + // c >= n is assumed, so the second disjunct is true + assertEquals(-1, cost(assumptions(tb.geq(c, n)))); + } + + @Test + public void usefulWhenIndexInRange() { + // 0 <= c < n leaves only p(c): the instance is not trivially true + assertNotEquals(-1, cost(assumptions(tb.geq(c, tb.zero()), tb.lt(c, n)))); + } + + @Test + public void usefulWhenNothingKnown() { + // without any range assumption the element property remains, so not useless + assertNotEquals(-1, cost(assumptions())); + } +} diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TestTriggersSet.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TestTriggersSet.java index 9c9acf138de..8f635415269 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TestTriggersSet.java +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TestTriggersSet.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -265,6 +266,61 @@ public void conjunctionYieldsOneTriggerPerClause() { assertEquals(expected, actual); } + /** The trigger terms of a multi-trigger's elements. */ + private static Set elementTerms(Trigger trigger) { + final Set terms = new HashSet<>(); + for (final Trigger element : ((MultiTrigger) trigger).elements()) { + terms.add(element.getTriggerTerm()); + } + return terms; + } + + @Test + public void elementsWithDisjointVariablesYieldOneMultiTrigger() { + // forall x. forall y. (pr(x) | ps(y)): neither literal covers both clause variables, so + // each is an element, and their only cover is the pair. + final JTerm all = parseTerm("\\forall r x;(\\forall s y;(pr(x) | ps(y)))"); + final ImmutableSet triggers = + TriggersSet.create(all, proof.getServices()).getAllTriggers(); + assertEquals(1, triggers.size()); + final Trigger multi = triggers.iterator().next(); + assertTrue(multi instanceof MultiTrigger, "the one trigger is the covering pair"); + final JTerm clause = all.sub(0).sub(0); + final Set expected = new HashSet<>(); + expected.add(clause.sub(0)); // pr(x) + expected.add(clause.sub(1)); // ps(y) + assertEquals(expected, elementTerms(multi)); + } + + @Test + public void aLiteralCoveringAllVariablesSuppressesTheCoverSearch() { + // forall x. forall y. (pr(x) | prs(x,y)): prs(x,y) covers both variables and is a + // uni-trigger; pr(x) alone covers nothing further, so no multi-trigger arises. + final JTerm all = parseTerm("\\forall r x;(\\forall s y;(pr(x) | prs(x,y)))"); + final ImmutableSet triggers = + TriggersSet.create(all, proof.getServices()).getAllTriggers(); + assertEquals(1, triggers.size()); + final Trigger uni = triggers.iterator().next(); + assertFalse(uni instanceof MultiTrigger, "the covering literal is a plain uni-trigger"); + assertEquals(all.sub(0).sub(0).sub(1), uni.getTriggerTerm()); // prs(x,y) + } + + @Test + public void overlappingElementsYieldEveryMinimalCover() { + // forall x,y,z. (prs(x,y) | pst(y,z) | prt(x,z)): each pair of literals covers all three + // variables and no literal is redundant in its pair, so the three pairs are exactly the + // minimal covers; the triple is not minimal and must not appear. + final JTerm all = parseTerm( + "\\forall r x;(\\forall s y;(\\forall t z;(prs(x,y) | pst(y,z) | prt(x,z))))"); + final ImmutableSet triggers = + TriggersSet.create(all, proof.getServices()).getAllTriggers(); + assertEquals(3, triggers.size()); + for (final Trigger trigger : triggers) { + assertTrue(trigger instanceof MultiTrigger, "every cover is a pair of elements"); + assertEquals(2, elementTerms(trigger).size(), "minimal covers have two elements"); + } + } + @Test public void bodyWithoutOuterVariableHasNoTriggers() { // forall x. forall y. ps(y): no literal mentions the OUTER variable x, so the From 40a644e09cd75bba4b995ad81ac3a300ed92469c Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Sun, 19 Jul 2026 18:04:19 +0200 Subject: [PATCH 10/15] Make the new quantifier theory aware triggering user configurable. - The classic option is the safe fallback (which might go away once trust into the new ones is established) The option is resolved once when a strategy is built, like every other strategy option: the instantiation generator, the prediction feature and the tie-break feature receive it at construction instead of reading the proof settings per candidate, and the trigger-set cache records which supports built an entry, so a lookup under the other setting rebuilds it. with AI tooling support --- .../ilkd/key/settings/StrategySettings.java | 11 ++ .../de/uka/ilkd/key/strategy/FOLStrategy.java | 28 ++- .../key/strategy/JFOLStrategyFactory.java | 28 ++- .../ilkd/key/strategy/StrategyProperties.java | 22 ++- .../HeuristicInstantiation.java | 24 ++- .../quantifierHeuristics/Instantiation.java | 186 ++++++++++++++---- .../InstantiationCost.java | 15 +- .../InstantiationTieBreakFeature.java | 78 ++++++++ .../quantifierHeuristics/TriggersSet.java | 153 ++++++++------ .../uka/ilkd/key/settings/SettingsTest.java | 1 + .../testcase/classpath/classpath.key.proof | 185 +++++++++++++++++ 11 files changed, 609 insertions(+), 122 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationTieBreakFeature.java create mode 100644 key.core/src/test/resources/testcase/classpath/classpath.key.proof diff --git a/key.core/src/main/java/de/uka/ilkd/key/settings/StrategySettings.java b/key.core/src/main/java/de/uka/ilkd/key/settings/StrategySettings.java index 491b48e0348..56ce8549cfe 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/settings/StrategySettings.java +++ b/key.core/src/main/java/de/uka/ilkd/key/settings/StrategySettings.java @@ -234,6 +234,17 @@ public StrategyProperties getActiveStrategyProperties() { return (StrategyProperties) strategyProperties.clone(); } + /** + * Reads a single active strategy property without copying the whole map. Cheap enough to call + * from the cost path, unlike {@link #getActiveStrategyProperties()}. + * + * @param key a strategy property key + * @return the active value for {@code key}, or {@code null} if unset + */ + public String getActiveStrategyProperty(String key) { + return strategyProperties.getProperty(key); + } + /** * sets the strategy properties if different from current ones */ diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java index 2d0680f0089..c4cda4a412e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/FOLStrategy.java @@ -385,7 +385,8 @@ private void setupQuantifierInstantiation(RuleSetDispatchFeature d) { if (quantifierInstantiatedEnabled()) { final TermBuffer varInst = new TermBuffer(); final Feature branchPrediction = InstantiationCostScalerFeature - .create(InstantiationCost.create(varInst), allowQuantifierSplitting()); + .create(InstantiationCost.create(varInst, classicTriggers()), + allowQuantifierSplitting()); bindRuleSet(d, "gamma", SumFeature.createSum(FocusInAntecFeature.getInstance(), @@ -393,8 +394,13 @@ private void setupQuantifierInstantiation(RuleSetDispatchFeature d) { add(ff.quantifiedClauseSet, instQuantifiersWithQueries() ? longTermConst(0) : ff.notContainsExecutable)), - forEach(varInst, HeuristicInstantiation.INSTANCE, - add(instantiate("t", varInst), branchPrediction, longConst(10))))); + forEach(varInst, HeuristicInstantiation.forOption(classicTriggers()), + add(instantiate("t", varInst), + add(branchPrediction, longConst(10), + // orders candidates of one predicted-cost band by their + // connection to the sequent instead of formula position + InstantiationTieBreakFeature.create(varInst, + triggersOption())))))); final TermBuffer splitInst = new TermBuffer(); bindRuleSet(d, "triggered", @@ -413,8 +419,10 @@ private void setupQuantifierInstantiationApproval(RuleSetDispatchFeature d) { 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")), + not(sum(varInst, HeuristicInstantiation.forOption(classicTriggers()), + not(eq(instOf("t"), varInst)))), + InstantiationCostScalerFeature.create( + InstantiationCost.create(instOf("t"), classicTriggers()), longConst(0)))); final TermBuffer splitInst = new TermBuffer(); @@ -597,6 +605,16 @@ private Feature allowQuantifierSplitting() { return inftyConst(); } + /** the value of the trigger option, fixed when this strategy was constructed */ + private String triggersOption() { + return strategyProperties.getProperty(StrategyProperties.TRIGGERS_OPTIONS_KEY); + } + + /** whether the classic trigger selection is in effect for this strategy */ + private boolean classicTriggers() { + return StrategyProperties.TRIGGERS_CLASSIC.equals(triggersOption()); + } + 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/JFOLStrategyFactory.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/JFOLStrategyFactory.java index 2927cd47725..104acbd03fe 100644 --- 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 @@ -5,6 +5,7 @@ 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; @@ -34,6 +35,19 @@ public class JFOLStrategyFactory implements StrategyFactory { with terms that occur in a sequent, also if this
\ might cause proof splitting."""; + public static final String TOOL_TIP_TRIGGERS_BEST = + "Instantiate quantified formulas using knowledge about arrays and the heap, with the" + + " most informative ordering of the instances to try. Recommended.
" + + "Adds a small per-step cost on very large proof states."; + public static final String TOOL_TIP_TRIGGERS_GOOD = + "Instantiate quantified formulas using knowledge about arrays and the heap, with a" + + " lighter-weight ordering of the instances.
" + + "Close to Best, with less per-step overhead on large proof states."; + public static final String TOOL_TIP_TRIGGERS_CLASSIC = + "Instantiate quantified formulas without the knowledge about arrays and the heap, and" + + " without ordering the instances.
" + + "The previous behaviour; use only if a proof was tuned to it."; + @Override public Strategy create(Proof proof, StrategyProperties strategyProperties) { return new JFOLStrategy(proof, strategyProperties); @@ -41,7 +55,8 @@ public Strategy create(Proof proof, StrategyProperties strategyProperties) private static OneOfStrategyPropertyDefinition getQuantifierTreatment() { return new OneOfStrategyPropertyDefinition(StrategyProperties.QUANTIFIERS_OPTIONS_KEY, - "Quantifier treatment", 2, + "Quantifier treatment", null, 2, + new AbstractStrategyPropertyDefinition[] { getTheorySupport() }, new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_NONE, "None", TOOL_TIP_QUANTIFIER_NONE, 2, 4), new StrategyPropertyValueDefinition(StrategyProperties.QUANTIFIERS_NON_SPLITTING, @@ -53,6 +68,17 @@ private static OneOfStrategyPropertyDefinition getQuantifierTreatment() { TOOL_TIP_QUANTIFIER_FREE, 6, 2)); } + private static OneOfStrategyPropertyDefinition getTheorySupport() { + return new OneOfStrategyPropertyDefinition(StrategyProperties.TRIGGERS_OPTIONS_KEY, + "Theory support:", + new StrategyPropertyValueDefinition(StrategyProperties.TRIGGERS_BEST, "Best", + TOOL_TIP_TRIGGERS_BEST), + new StrategyPropertyValueDefinition(StrategyProperties.TRIGGERS_GOOD, "Good", + TOOL_TIP_TRIGGERS_GOOD), + new StrategyPropertyValueDefinition(StrategyProperties.TRIGGERS_CLASSIC, "Classic", + TOOL_TIP_TRIGGERS_CLASSIC)); + } + @Override public StrategySettingsDefinition getSettingsDefinition() { final OneOfStrategyPropertyDefinition quantifierTreatment = getQuantifierTreatment(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/StrategyProperties.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/StrategyProperties.java index 3ccc76b424e..82dfc3ab3a8 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/StrategyProperties.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/StrategyProperties.java @@ -79,6 +79,19 @@ public final class StrategyProperties extends Properties { "QUANTIFIERS_NON_SPLITTING_WITH_PROGS"; public static final String QUANTIFIERS_INSTANTIATE = "QUANTIFIERS_INSTANTIATE"; + /** + * The quantifier instantiation treatment. {@link #TRIGGERS_BEST} and {@link #TRIGGERS_GOOD} + * both use the theory-aware trigger selection (heap and array reads); they differ in how tied + * candidates are ordered, {@code BEST} by the proving-polarity connection to the sequent, + * {@code GOOD} by generation with a lighter ordering. {@link #TRIGGERS_CLASSIC} uses the plain + * equality-and-integer trigger selection with no candidate ordering, matching the previous + * behaviour. + */ + public static final String TRIGGERS_OPTIONS_KEY = "TRIGGERS_OPTIONS_KEY"; + public static final String TRIGGERS_BEST = "TRIGGERS_BEST"; + public static final String TRIGGERS_GOOD = "TRIGGERS_GOOD"; + public static final String TRIGGERS_CLASSIC = "TRIGGERS_CLASSIC"; + public static final String VBT_PHASE = "VBT_PHASE"; // Used for verification-based testing public static final String VBT_SYM_EX = "VBT_SYM_EX"; public static final String VBT_QUAN_INST = "VBT_QUAN_INST"; @@ -170,7 +183,9 @@ public final class StrategyProperties extends Properties { NON_LIN_ARITH_OPTIONS_KEY, NON_LIN_ARITH_NONE, NON_LIN_ARITH_DEF_OPS, NON_LIN_ARITH_COMPLETION, OSS_OPTIONS_KEY, OSS_ON, OSS_OFF, QUANTIFIERS_OPTIONS_KEY, QUANTIFIERS_NONE, QUANTIFIERS_NON_SPLITTING, QUANTIFIERS_NON_SPLITTING_WITH_PROGS, - QUANTIFIERS_INSTANTIATE, VBT_PHASE, VBT_SYM_EX, VBT_QUAN_INST, VBT_MODEL_GEN, + QUANTIFIERS_INSTANTIATE, TRIGGERS_OPTIONS_KEY, TRIGGERS_BEST, TRIGGERS_GOOD, + TRIGGERS_CLASSIC, VBT_PHASE, + VBT_SYM_EX, VBT_QUAN_INST, VBT_MODEL_GEN, CLASS_AXIOM_OFF, CLASS_AXIOM_DELAYED, CLASS_AXIOM_FREE, AUTO_INDUCTION_OPTIONS_KEY, AUTO_INDUCTION_OFF, AUTO_INDUCTION_RESTRICTED, AUTO_INDUCTION_ON, AUTO_INDUCTION_LEMMA_ON, USER_TACLETS_OPTIONS_KEY_BASE, USER_TACLETS_OFF, USER_TACLETS_LOW, USER_TACLETS_HIGH, @@ -196,6 +211,7 @@ public final class StrategyProperties extends Properties { DEFAULT_MAP.setProperty(QUERYAXIOM_OPTIONS_KEY, QUERYAXIOM_ON); DEFAULT_MAP.setProperty(NON_LIN_ARITH_OPTIONS_KEY, NON_LIN_ARITH_NONE); DEFAULT_MAP.setProperty(QUANTIFIERS_OPTIONS_KEY, QUANTIFIERS_NON_SPLITTING_WITH_PROGS); + DEFAULT_MAP.setProperty(TRIGGERS_OPTIONS_KEY, TRIGGERS_BEST); for (int i = 1; i <= USER_TACLETS_NUM; ++i) { DEFAULT_MAP.setProperty(userTacletsOptionsKey(i), USER_TACLETS_OFF); } @@ -222,6 +238,7 @@ public StrategyProperties() { put(NON_LIN_ARITH_OPTIONS_KEY, DEFAULT_MAP.get(NON_LIN_ARITH_OPTIONS_KEY)); put(OSS_OPTIONS_KEY, DEFAULT_MAP.get(OSS_OPTIONS_KEY)); put(QUANTIFIERS_OPTIONS_KEY, DEFAULT_MAP.get(QUANTIFIERS_OPTIONS_KEY)); + put(TRIGGERS_OPTIONS_KEY, DEFAULT_MAP.get(TRIGGERS_OPTIONS_KEY)); for (int i = 1; i <= USER_TACLETS_NUM; ++i) { put(userTacletsOptionsKey(i), DEFAULT_MAP.get(userTacletsOptionsKey(i))); } @@ -254,6 +271,7 @@ public static StrategyProperties read(Properties p) { sp.put(NON_LIN_ARITH_OPTIONS_KEY, readSingleOption(p, NON_LIN_ARITH_OPTIONS_KEY)); sp.put(OSS_OPTIONS_KEY, readSingleOption(p, OSS_OPTIONS_KEY)); sp.put(QUANTIFIERS_OPTIONS_KEY, readSingleOption(p, QUANTIFIERS_OPTIONS_KEY)); + sp.put(TRIGGERS_OPTIONS_KEY, readSingleOption(p, TRIGGERS_OPTIONS_KEY)); for (int i = 1; i <= USER_TACLETS_NUM; ++i) { sp.put(userTacletsOptionsKey(i), readSingleOption(p, userTacletsOptionsKey(i))); } @@ -302,6 +320,7 @@ public static void setDefaultStrategyProperties(StrategyProperties sp, sp.setProperty(OSS_OPTIONS_KEY, OSS_ON); sp.setProperty(MPS_OPTIONS_KEY, MPS_MERGE); sp.setProperty(QUERY_OPTIONS_KEY, QUERY_RESTRICTED); + sp.setProperty(TRIGGERS_OPTIONS_KEY, TRIGGERS_BEST); sp.setProperty(NON_LIN_ARITH_OPTIONS_KEY, NON_LIN_ARITH_DEF_OPS); sp.setProperty(AUTO_INDUCTION_OPTIONS_KEY, @@ -412,6 +431,7 @@ public void write(Properties p) { p.put(STRATEGY_PROPERTY + NON_LIN_ARITH_OPTIONS_KEY, get(NON_LIN_ARITH_OPTIONS_KEY)); p.put(STRATEGY_PROPERTY + OSS_OPTIONS_KEY, get(OSS_OPTIONS_KEY)); p.put(STRATEGY_PROPERTY + QUANTIFIERS_OPTIONS_KEY, get(QUANTIFIERS_OPTIONS_KEY)); + p.put(STRATEGY_PROPERTY + TRIGGERS_OPTIONS_KEY, get(TRIGGERS_OPTIONS_KEY)); for (int i = 1; i <= USER_TACLETS_NUM; ++i) { p.put(STRATEGY_PROPERTY + userTacletsOptionsKey(i), get(userTacletsOptionsKey(i))); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeuristicInstantiation.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeuristicInstantiation.java index 3d5dece4ff9..248e9a9c49b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeuristicInstantiation.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/HeuristicInstantiation.java @@ -22,9 +22,27 @@ public class HeuristicInstantiation implements TermGenerator { - public final static TermGenerator INSTANCE = new HeuristicInstantiation(); + private static final HeuristicInstantiation THEORY = new HeuristicInstantiation(false); + private static final HeuristicInstantiation CLASSIC = new HeuristicInstantiation(true); - private HeuristicInstantiation() {} + /** whether instances are computed with the classic trigger selection */ + private final boolean classicTriggers; + + private HeuristicInstantiation(boolean classicTriggers) { + this.classicTriggers = classicTriggers; + } + + /** + * The generator for the given setting of the trigger option. The setting is fixed at + * strategy construction, like every other strategy option; reading it per generated + * instance would take a synchronized settings lookup in the middle of proof search. + * + * @param classicTriggers whether the classic trigger selection is in effect + * @return the generator + */ + public static TermGenerator forOption(boolean classicTriggers) { + return classicTriggers ? CLASSIC : THEORY; + } @Override public Iterator generate(RuleApp app, PosInOccurrence pos, Goal goal, @@ -33,7 +51,7 @@ public Iterator generate(RuleApp app, PosInOccurrence pos, Goal goal, final Term qf = pos.sequentFormula().formula(); final Instantiation ia = - Instantiation.create(qf, goal.sequent(), goal.proof().getServices()); + Instantiation.create(qf, goal.sequent(), goal.proof().getServices(), classicTriggers); final QuantifiableVariable var = qf.varsBoundHere(0).last(); assert var != null; return new HIIterator(ia.getSubstitution().iterator(), var, goal.proof().getServices()); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java index 34e396264b6..cdd2f5dd3f4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/Instantiation.java @@ -3,7 +3,10 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy.quantifierHeuristics; +import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import de.uka.ilkd.key.java.Services; @@ -12,6 +15,8 @@ import de.uka.ilkd.key.logic.TermServices; import de.uka.ilkd.key.logic.op.ParametricFunctionInstance; import de.uka.ilkd.key.logic.op.Quantifier; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Proof; import org.key_project.logic.Term; import org.key_project.logic.op.QuantifiableVariable; @@ -26,6 +31,8 @@ import org.key_project.util.collection.ImmutableMap; import org.key_project.util.collection.ImmutableSet; +import static de.uka.ilkd.key.logic.equality.IrrelevantTermLabelsProperty.IRRELEVANT_TERM_LABELS_PROPERTY; + class Instantiation { @@ -41,18 +48,47 @@ class Instantiation { /** HashMap from instance(Term) to cost Long */ private final Map instancesWithCosts = new LinkedHashMap<>(); + /** + * The recorded instances bucketed by {@link Term#nameHash()}. Two terms equal up to term + * labels share that hash, so the label-insensitive duplicate check in + * {@link #addInstance(Substitution, long)} compares only within one bucket instead of + * scanning every recorded instance. + */ + private final Map> instancesByNameHash = new HashMap<>(); + + /** The tie-break scorer, prepared lazily on the first tie-break request and reused. */ + private QuantifierInstantiationTieBreak.Scorer scorer; + + /** The strategy the {@link #scorer} was prepared with; a change re-prepares it. */ + private QuantifierInstantiationTieBreak scorerStrategy; /** the TriggersSet of this allTerm */ private final TriggersSet triggersSet; - private Instantiation(Term allterm, Sequent seq, Services services) { + /** Equality reasoning over the sequent's assumed equalities, shared across cost predictions. */ + private final Congruence congruence; + + /** The sequent, kept for the tie-break view. */ + private final Sequent sequent; + + /** The services, kept for the tie-break view. */ + private final Services services; + + private Instantiation(Term allterm, Sequent seq, Services services, boolean classic) { + this.sequent = seq; + this.services = services; firstVar = allterm.varsBoundHere(0).get(0); matrix = TriggerUtils.discardQuantifiers(allterm); /* Terms bound in every formula on goal */ - triggersSet = TriggersSet.create((JTerm) allterm, services); + triggersSet = TriggersSet.create((JTerm) allterm, services, classic); assumedLiterals = initAssertLiterals(seq, services); + congruence = new Congruence(assumedLiterals, services); + assumedLiterals = normalizeAll(assumedLiterals); addInstances(sequentToTerms(seq), services); - addStoreCoordinateInstances((JTerm) matrix, services); + // write-coordinate candidates are part of the theory-aware selection, dropped in classic + if (!classic) { + addStoreCoordinateInstances((JTerm) matrix, services); + } } /** @@ -101,7 +137,8 @@ private void collectWrittenIndices(JTerm heap, JTerm obj, Services services) { } } - private record Cached(Term qf, Sequent seq, Instantiation result) { + private record Cached(Proof proof, Term qf, Sequent seq, boolean classic, + Instantiation result) { } /** @@ -115,13 +152,20 @@ private record Cached(Term qf, Sequent seq, Instantiation result) { */ private static final ThreadLocal lastCreate = new ThreadLocal<>(); - static Instantiation create(Term qf, Sequent seq, Services services) { + static Instantiation create(Term qf, Sequent seq, Services services, boolean classic) { + final Proof proof = services.getProof(); final Cached cached = lastCreate.get(); - if (cached != null && qf == cached.qf() && seq == cached.seq()) { + if (cached != null && qf == cached.qf() && seq == cached.seq() + && classic == cached.classic()) { return cached.result(); } - final Instantiation result = new Instantiation(qf, seq, services); - lastCreate.set(new Cached(qf, seq, result)); + if (cached != null && proof != cached.proof()) { + // The memo belongs to another proof. Drop it before computing, so the other + // proof's sequent stays reachable only while this entry is in use. + lastCreate.remove(); + } + final Instantiation result = new Instantiation(qf, seq, services, classic); + lastCreate.set(new Cached(proof, qf, seq, classic, result)); return result; } @@ -134,10 +178,10 @@ private static ImmutableSet sequentToTerms(Sequent seq) { } /** - * @param terms on which trigger are doning matching search every Substitution s by - * matching triggers from triggersSet to terms - * compute their cost and store the pair of instance (Term) and cost(Long) in - * instancesCostCache + * For each trigger, match it against the sequent terms and store every resulting instantiation + * together with its predicted cost in {@code instancesWithCosts}. + * + * @param terms the sequent terms the triggers are matched against */ private void addInstances(ImmutableSet terms, Services services) { for (final Trigger t : triggersSet.getAllTriggers()) { @@ -145,52 +189,72 @@ private void addInstances(ImmutableSet terms, Services services) { addInstance(sub, services); } } - // if ( instancesWithCosts.isEmpty () ) - // ensure that there is always at least one instantiation - // addArbitraryInstance (); - } - - private void addArbitraryInstance(Services services) { - ImmutableMap varMap = - DefaultImmutableMap.nilMap(); - - for (QuantifiableVariable v : triggersSet.getUniQuantifiedVariables()) { - final Term inst = createArbitraryInstantiation(v, services); - varMap = varMap.put(v, inst); - } - - addInstance(new Substitution(varMap), services); - } - - private Term createArbitraryInstantiation(QuantifiableVariable var, Services services) { - return services.getTermBuilder().func( - services.getJavaDLTheory().getCastSymbol(var.sort(), services), - services.getTermBuilder().zero()); } private void addInstance(Substitution sub, Services services) { final long cost = PredictCostProver.computerInstanceCost(sub, (JTerm) getMatrix(), - assumedLiterals, services); + assumedLiterals, congruence, services); if (cost != -1) { addInstance(sub, cost); } } /** - * add instance of var in sub with cost to - * instancesCostCache if this instance is exist, compare thire cost and store the - * less one. + * Pre-normalises the assumed literals once through the congruence, so each candidate's cost + * prediction reuses the result instead of re-normalising them. + * + * @param lits the assumed literals + * @return the normalised literals, or {@code lits} unchanged when the congruence is trivial + */ + private ImmutableSet normalizeAll(ImmutableSet lits) { + if (congruence.isTrivial()) { + return lits; + } + ImmutableSet res = DefaultImmutableSet.nil(); + for (final JTerm l : lits) { + res = res.add(congruence.normalize(l)); + } + return res; + } + + /** + * Records the instance chosen by sub for the quantified variable with its + * predicted cost, keeping the least cost when the instance is recorded already. + * + * The same instance can be found through different triggers whose matches differ only in term + * labels: one match picks the term up with an origin label, another without. Term equality is + * label sensitive, so both variants would enter the table as separate candidates, and the + * labels would decide which of the two is enumerated first. The table keeps one entry per + * instance up to term labels: a later variant merges into the entry of the first one found. * - * @param sub - * @param cost + * @param sub the substitution providing the instance + * @param cost the predicted cost of the instance */ private void addInstance(Substitution sub, long cost) { final Term inst = sub.getSubstitutedTerm(firstVar); - final Long oldCost = instancesWithCosts.get(inst); + Term key = inst; + Long oldCost = instancesWithCosts.get(inst); + if (oldCost == null) { + final List bucket = instancesByNameHash.get(inst.nameHash()); + if (bucket != null) { + for (final Term existing : bucket) { + if (((JTerm) existing).equalsModProperty(inst, + IRRELEVANT_TERM_LABELS_PROPERTY)) { + key = existing; + oldCost = instancesWithCosts.get(existing); + break; + } + } + } + if (oldCost == null) { + instancesByNameHash.computeIfAbsent(inst.nameHash(), h -> new ArrayList<>(2)) + .add(inst); + } + } if (oldCost == null || oldCost >= cost) { - instancesWithCosts.put(inst, cost); + instancesWithCosts.put(key, cost); } } @@ -223,8 +287,9 @@ private ImmutableSet initAssertLiterals(Sequent seq, /** * Try to find the cost of an instance(inst) according its quantified formula and current goal. */ - static RuleAppCost computeCost(Term inst, Term form, Sequent seq, Services services) { - return create(form, seq, services).computeCostHelp(inst); + static RuleAppCost computeCost(Term inst, Term form, Sequent seq, Services services, + boolean classic) { + return create(form, seq, services, classic).computeCostHelp(inst); } private RuleAppCost computeCostHelp(Term inst) { @@ -245,6 +310,41 @@ private RuleAppCost computeCostHelp(Term inst) { return NumberRuleAppCost.create(cost); } + /** + * The within-band tie-break cost of an instance, from the given tie-break strategy. Creates (or + * reuses) the instantiation for the quantified formula, prepares the strategy's per-formula + * facts once, and scores the instance. + * + * @param inst the candidate instance + * @param form the quantified formula + * @param seq the sequent + * @param goal the goal, for the branch history the generation signal needs + * @param services access to the theory operators + * @param classic whether the classic trigger selection is active + * @param strategy the tie-break strategy + * @return the tie-break cost + */ + static RuleAppCost computeTieBreak(Term inst, Term form, Sequent seq, + Goal goal, Services services, boolean classic, + QuantifierInstantiationTieBreak strategy) { + return create(form, seq, services, classic).tieBreak(inst, goal, strategy); + } + + /** + * The tie-break cost of an instance, delegating to {@code strategy}. The strategy's per-formula + * facts are prepared once on the first request and reused; a change of strategy re-prepares + * them. + */ + private RuleAppCost tieBreak(Term inst, Goal goal, + QuantifierInstantiationTieBreak strategy) { + if (scorer == null || scorerStrategy != strategy) { + scorer = strategy.prepare(new QuantifierInstantiationTieBreak.View( + instancesWithCosts.keySet(), sequent, goal, services)); + scorerStrategy = strategy; + } + return NumberRuleAppCost.create(scorer.tieBreak(inst)); + } + /** get all instances from instancesCostCache subsCache */ ImmutableSet getSubstitution() { ImmutableSet res = DefaultImmutableSet.nil(); diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationCost.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationCost.java index 749f1c5de52..d27163c8736 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationCost.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationCost.java @@ -24,12 +24,16 @@ public class InstantiationCost implements Feature { final private ProjectionToTerm varInst; - private InstantiationCost(ProjectionToTerm var) { + /** whether the prediction runs with the classic trigger selection */ + private final boolean classicTriggers; + + private InstantiationCost(ProjectionToTerm var, boolean classicTriggers) { varInst = var; + this.classicTriggers = classicTriggers; } - public static Feature create(ProjectionToTerm varInst) { - return new InstantiationCost(varInst); + public static Feature create(ProjectionToTerm varInst, boolean classicTriggers) { + return new InstantiationCost(varInst, classicTriggers); } /** @@ -41,9 +45,10 @@ public static Feature create(ProjectionToTerm varInst) { assert pos != null : "Projection is only applicable to rules with find"; final Term formula = pos.sequentFormula().formula(); - final var instance = varInst.toTerm(app, pos, (de.uka.ilkd.key.proof.Goal) goal, mState); + final de.uka.ilkd.key.proof.Goal jgoal = (de.uka.ilkd.key.proof.Goal) goal; + final var instance = varInst.toTerm(app, pos, jgoal, mState); return Instantiation.computeCost(instance, formula, goal.sequent(), - (Services) goal.proof().getServices()); + (Services) goal.proof().getServices(), classicTriggers); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationTieBreakFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationTieBreakFeature.java new file mode 100644 index 00000000000..2e34d5f271c --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/InstantiationTieBreakFeature.java @@ -0,0 +1,78 @@ +/* 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.quantifierHeuristics; + +import de.uka.ilkd.key.java.Services; +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.strategy.StrategyProperties; + +import org.key_project.logic.Term; +import org.key_project.prover.proof.ProofGoal; +import org.key_project.prover.rules.RuleApp; +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.NumberRuleAppCost; +import org.key_project.prover.strategy.costbased.RuleAppCost; +import org.key_project.prover.strategy.costbased.feature.Feature; +import org.key_project.prover.strategy.costbased.termProjection.ProjectionToTerm; + +import org.jspecify.annotations.NonNull; + +/** + * Orders quantifier instantiation candidates whose predicted cost is equal, so the choice within a + * cost band falls to the content of the instance instead of the position of the quantified formula. + * The ordering signal follows the quantifier treatment: {@code Best} + * ({@link StrategyProperties#TRIGGERS_BEST}) uses {@link PolarityTieBreak}, {@code Good} + * ({@link StrategyProperties#TRIGGERS_GOOD}) uses {@link GenPolTieBreak}, and {@code Classic} + * ({@link StrategyProperties#TRIGGERS_CLASSIC}) adds no tie-break: instances keep the order of + * their positions in the sequent. The values stay far below the distance of the predicted cost + * bands, so the prediction + * itself is never overridden. + */ +public class InstantiationTieBreakFeature implements Feature { + + private final ProjectionToTerm varInst; + /** the resolved tie-break, or {@code null} for the classic option */ + private final QuantifierInstantiationTieBreak strategy; + + private InstantiationTieBreakFeature(ProjectionToTerm var, + QuantifierInstantiationTieBreak strategy) { + varInst = var; + this.strategy = strategy; + } + + /** + * The feature for the given setting of the trigger option, resolved once at strategy + * construction like every other strategy option. + * + * @param varInst the projection to the candidate instance + * @param triggersOption the value of {@link StrategyProperties#TRIGGERS_OPTIONS_KEY} + * @return the feature + */ + public static Feature create(ProjectionToTerm varInst, String triggersOption) { + final QuantifierInstantiationTieBreak strategy = switch (triggersOption) { + case StrategyProperties.TRIGGERS_GOOD -> GenPolTieBreak.INSTANCE; + case StrategyProperties.TRIGGERS_CLASSIC -> null; + default -> PolarityTieBreak.INSTANCE; + }; + return new InstantiationTieBreakFeature(varInst, strategy); + } + + @Override + public > RuleAppCost computeCost(RuleApp app, + PosInOccurrence pos, Goal goal, MutableState mState) { + assert pos != null : "Projection is only applicable to rules with find"; + + final de.uka.ilkd.key.proof.Goal jgoal = (de.uka.ilkd.key.proof.Goal) goal; + if (strategy == null) { + // classic orders instances by their position in the sequent alone + return NumberRuleAppCost.getZeroCost(); + } + + final Term formula = pos.sequentFormula().formula(); + final Term instance = varInst.toTerm(app, pos, jgoal, mState); + return Instantiation.computeTieBreak(instance, formula, goal.sequent(), jgoal, + (Services) goal.proof().getServices(), false, strategy); + } +} diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java index f354965ddb4..568c5438de4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/quantifierHeuristics/TriggersSet.java @@ -4,6 +4,7 @@ package de.uka.ilkd.key.strategy.quantifierHeuristics; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -24,8 +25,7 @@ import org.key_project.util.collection.ImmutableSet; /** - * This class is used to select and store Triggers for a quantified formula in Prenex - * CNF(PCNF). + * Selects and stores the triggers for a quantified formula in prenex conjunctive normal form. */ public class TriggersSet { @@ -37,43 +37,71 @@ public class TriggersSet { * equality * is consulted before integer arithmetic, matching the original prover. */ - static final java.util.List THEORY_SUPPORTS = - java.util.List.of(new HeapArrayTheorySupport(), new EqualityTheorySupport(), + static final List THEORY_SUPPORTS = + List.of(new HeapArrayTheorySupport(), new EqualityTheorySupport(), new IntegerTheorySupport()); - /** Quantified formula of PCNF */ + /** + * The classic trigger selection: equality and integer rejection only, without the + * symbolic-execution supports. The strategy option {@code TRIGGERS_CLASSIC} selects it. + */ + private static final List CLASSIC_SUPPORTS = + List.of(new EqualityTheorySupport(), new IntegerTheorySupport()); + + /** The quantified formula in prenex CNF. */ private final JTerm allTerm; + /** Whether this set was built with the classic supports; part of the cache decision. */ + private final boolean classic; /** * The triggers collected while this set is built. A hash set answers the duplicate check in * constant time, whereas {@link ImmutableSet#add} scans the elements it already holds, which * costs quadratic time in the number of triggers a clause yields. Collection order is kept so - * {@link #getAllTriggers()} can hand out exactly the set repeated adds would have produced. + * {@link #getAllTriggers()} hands out exactly the set repeated adds would have produced. */ private final LinkedHashSet collectedTriggers = new LinkedHashSet<>(); - - /** Built from {@link #collectedTriggers} on first request. */ - private ImmutableSet allTriggers; + /** All triggers for the formula, built from the collected ones by the constructor. */ + private final ImmutableSet allTriggers; + /** Maps each trigger subterm of the formula to its trigger. */ + private final Map termToTrigger = new LinkedHashMap<>(); /** - * a HashMap from Term to Trigger which stores different - * subterms of allTerm with its according trigger + * The subterms whose theory triggers were already provided. The derived triggers depend + * only on the subterm and its variables, but each provision builds them around fresh + * metavariables, so a second occurrence of the same subterm in another clause would + * register unequal copies of the same triggers. */ - private final Map termToTrigger = new LinkedHashMap<>(); - /** all universal variables of allTerm */ + private final Set theoryTriggersProvidedFor = new HashSet<>(); + /** All universal variables of the formula. */ private final ImmutableSet uniQuantifiedVariables; /** * Replacement of the bound variables in allTerm with metavariables and constants */ private final Substitution replacementWithMVs; + /** + * The theory supports consulted for trigger rejection and provision. Under the classic trigger + * selection only the classic supports (equality and integer) are kept. + */ + private final List supports; - private TriggersSet(JTerm allTerm, Services services) { + private TriggersSet(JTerm allTerm, Services services, boolean classic) { this.allTerm = allTerm; + this.classic = classic; + this.supports = classic ? CLASSIC_SUPPORTS : THEORY_SUPPORTS; replacementWithMVs = ReplacerOfQuanVariablesWithMetavariables.createSubstitutionForVars(allTerm, services); uniQuantifiedVariables = collectUniversalVariables(allTerm); initTriggers(services); + // Adding to an immutable set prepends, so building it by repeated adds leaves the + // triggers in the reverse of the order they were collected. Reverse here as well, so + // the trigger order the strategy sees does not depend on how the set was assembled. + allTriggers = DefaultImmutableSet + .fromImmutableList(ImmutableList.fromList(collectedTriggers).reverse()); } static TriggersSet create(JTerm allTerm, Services services) { + return create(allTerm, services, false); + } + + static TriggersSet create(JTerm allTerm, Services services, boolean classic) { final Map triggerSetCache = services.getCaches().getTriggerSetCache(); allTerm = TermLabelManager.removeIrrelevantLabels(allTerm, services); @@ -83,9 +111,11 @@ static TriggersSet create(JTerm allTerm, Services services) { trs = triggerSetCache.get(allTerm); } - if (trs == null) { + // A set built under the other trigger option is not reused: the option selects the + // theory supports, so the triggers differ. + if (trs == null || trs.classic != classic) { // add check whether it is in PCNF - trs = new TriggersSet(allTerm, services); + trs = new TriggersSet(allTerm, services, classic); synchronized (triggerSetCache) { triggerSetCache.put(allTerm, trs); } @@ -94,8 +124,8 @@ static TriggersSet create(JTerm allTerm, Services services) { } /** - * @param allterm - * @return return all univesal variables of allterm + * @param allterm a quantified formula + * @return the universal variables bound in the formula */ private ImmutableSet collectUniversalVariables(JTerm allterm) { final var op = allterm.op(); @@ -109,9 +139,7 @@ private ImmutableSet collectUniversalVariables(JTerm allte return DefaultImmutableSet.nil(); } - /** - * initial all Triggers by finding triggers in every clauses - */ + /** Finds the triggers in every clause of the matrix. */ private void initTriggers(Services services) { final QuantifiableVariable firstVariable = allTerm.varsBoundHere(0).get(0); final var clauses = @@ -127,13 +155,15 @@ private void initTriggers(Services services) { } /** + * Creates the uni-trigger for a term, or returns the cached one. * - * @param trigger a Term - * @param qvs all universal variables of trigger - * @param isUnify true if triggercontains existential variable - * @param isElement true if the Trigger to be created is taken as a element of - * multi-trigger - * @return a Trigger with trigger as its term + * @param trigger the trigger term + * @param universalVariables the universal variables the trigger binds + * @param isUnify whether the trigger carries an existential variable and needs unification + * @param isElement whether the trigger is an element of a multi-trigger + * @param matchByUnification whether the trigger is matched by unification even against ground + * terms + * @return the uni-trigger for the term */ private Trigger createUniTrigger(JTerm trigger, ImmutableSet universalVariables, boolean isUnify, @@ -148,11 +178,12 @@ private Trigger createUniTrigger(JTerm trigger, } /** + * Creates a multi-trigger from the given elements. * - * @param trs - * @param clause a Term of clause form - * @param qvs all universal varaibles of all clause - * @return the MultTrigger for the given triggers + * @param elements the uni-trigger elements + * @param clause the clause the multi-trigger belongs to + * @param clauseVariables the universal variables of the clause + * @return the multi-trigger */ private Trigger createMultiTrigger(ImmutableSet elements, JTerm clause, ImmutableSet clauseVariables) { @@ -160,26 +191,21 @@ private Trigger createMultiTrigger(ImmutableSet elements, JTerm clause, } /** - * this class is used to find Triggers in a clause. And it will try to find - * triggers from every literals in this clause. Every substerm of literal that satify the - * conditions:(1)it should not be a variable, (2) it doesn't contain propersitional connectives, - * (3) it is not in loop, (4) it should contains all universal variables in the clause and the - * first variable of allTerm (5) it doesn't contain subtrigger, will be selected as - * an Uni-trigger. If a literal does not contain all universal variables in clause, a set of - * subterms of this literal will be selected as Multi-trigger's elements which are actually - * uni-triggers except that condition (2) will be changedand into that it contains all universal - * variables in the literal in. Afterwards, a set of multi-triggers will be constructed by - * combining thoes elements so that all variables in clause should be include by some of them. + * Finds the triggers in a clause. From each literal it selects the smallest subterm that is not + * a variable, contains no propositional connective, is not part of a loop, holds every + * universal + * variable of the clause and the first quantified variable, and has no sub-trigger of its own; + * such a subterm becomes a uni-trigger. A literal that does not hold every universal variable + * of + * the clause instead contributes multi-trigger elements, subterms that together cover the + * clause's variables, from which covering multi-triggers are built. */ private class ClauseTriggerFinder { final JTerm clause; - /** all unversal variables of clause */ + /** The universal variables of the clause. */ final ImmutableSet clauseVariables; - /** - * elements which are uni-trigges and will be used to construct several multi-triggers for - * clause - */ + /** The uni-trigger elements from which the clause's multi-triggers are built. */ private ImmutableSet elementsOfMultiTrigger = DefaultImmutableSet.nil(); public ClauseTriggerFinder(JTerm clause) { @@ -190,9 +216,10 @@ public ClauseTriggerFinder(JTerm clause) { } /** - * Searching uni-triggers and elements of multi-triggers in every literal in this - * clause and add those uni-triggers to the goal trigger set. At last construct - * multi-triggers from those elements. + * Finds the uni-triggers and multi-trigger elements in each literal of the clause, + * registers the uni-triggers, and then builds the covering multi-triggers. + * + * @param services access to the theory operators and term construction */ public void createTriggers(Services services) { final var literals = TriggerUtils.iteratorByOperator(clause, Junctor.OR); @@ -210,9 +237,12 @@ public void createTriggers(Services services) { } /** - * @param term one atom at the begining - * @param services the Services - * @return true if find any trigger from term + * Registers the maximal uni-triggers in the term: the triggers of its subterms if any of + * them yields one, otherwise the term itself. + * + * @param term a subterm of a literal + * @param services access to the theory operators and term construction + * @return whether a trigger was found in the term or its subterms */ private boolean addMaximalUniTriggers(JTerm term, Services services) { if (!mightContainTriggers(term)) { @@ -309,7 +339,7 @@ private boolean mightContainTriggers(JTerm term) { * rejects it as coordinate or connective material. */ private boolean isAcceptableTrigger(JTerm term, Services services) { - for (final QuantifierTheorySupport support : THEORY_SUPPORTS) { + for (final QuantifierTheorySupport support : supports) { if (support.rejectsAsTrigger(term, services)) { return false; } @@ -331,10 +361,12 @@ private boolean addUniTrigger(JTerm term, Services services) { // A theory's generalisation is a different term, not a weaker one: it can match where // the original does not and fail to match where the original does. Both are therefore // registered, so an instantiation reachable through either one stays reachable. - for (final QuantifierTheorySupport support : THEORY_SUPPORTS) { - for (final JTerm derived : support.provideTriggers(term, clauseVariables, - services)) { - registerUniTrigger(derived, true); + if (theoryTriggersProvidedFor.add(term)) { + for (final QuantifierTheorySupport support : supports) { + for (final JTerm derived : support.provideTriggers(term, clauseVariables, + services)) { + registerUniTrigger(derived, true); + } } } return true; @@ -477,13 +509,6 @@ public JTerm getQuantifiedFormula() { } public ImmutableSet getAllTriggers() { - if (allTriggers == null) { - // Adding to an immutable set prepends, so building it by repeated adds leaves the - // triggers in the reverse of the order they were collected. Reverse here as well, so - // the trigger order the strategy sees does not depend on how the set was assembled. - allTriggers = DefaultImmutableSet - .fromImmutableList(ImmutableList.fromList(collectedTriggers).reverse()); - } return allTriggers; } diff --git a/key.core/src/test/java/de/uka/ilkd/key/settings/SettingsTest.java b/key.core/src/test/java/de/uka/ilkd/key/settings/SettingsTest.java index 7a6b6535435..9e3a6554a32 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/settings/SettingsTest.java +++ b/key.core/src/test/java/de/uka/ilkd/key/settings/SettingsTest.java @@ -102,6 +102,7 @@ void proofSettings() { "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_BEST", "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", diff --git a/key.core/src/test/resources/testcase/classpath/classpath.key.proof b/key.core/src/test/resources/testcase/classpath/classpath.key.proof new file mode 100644 index 00000000000..24a3329c82d --- /dev/null +++ b/key.core/src/test/resources/testcase/classpath/classpath.key.proof @@ -0,0 +1,185 @@ +\profile "Java Profile"; + +\settings { + "Choice" : { + "JavaCard" : "JavaCard:on", + "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:ban", + "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_OFF", + "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_DEF_OPS", + "OSS_OPTIONS_KEY" : "OSS_ON", + "QUANTIFIERS_OPTIONS_KEY" : "QUANTIFIERS_NON_SPLITTING_WITH_PROGS", + "QUERYAXIOM_OPTIONS_KEY" : "QUERYAXIOM_ON", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", + "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", + "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", + "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_BEST", + "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" + } + } +} + +\programVariables { + cp.E x; +} + +\classpath "classpath"; +\javaSource "javaSource"; + +\problem { +wellFormed(heap) +==> + \<{ + cp.C1.field = 42; + }\> select<[int]>(heap, null, cp.C1::#field) + = Z(2(4(#))) + & \<{ + js.C2.m_C2(); + cp.C1.m_C1(); + cp.C.m_C(); + }\> true + & \<{ + x = cp.E.e4; + }\> x = select<[cp.E]>(heap, null, cp.E::#e4) +} + +\proof { +(keyLog "0" (keyUser "bubel" ) (keyVersion "5424ffff7125e9ba1109fd87159ce5bc47e27763")) + +(autoModeTime "10") + +(branch "dummy ID" +(rule "eqSymm" (formula "2") (term "0,1")) +(rule "activeUseStaticFieldWriteAccess" (formula "2") (term "0,0") (inst "#v0=i")) +(rule "activeUseStaticFieldReadAccess" (formula "2") (term "1")) +(rule "variableDeclarationAssign" (formula "2") (term "0,0")) +(rule "assignment_read_static_attribute" (formula "2") (term "1")) +(rule "variableDeclaration" (formula "2") (term "0,0") (newnames "i")) +(rule "assignment" (formula "2") (term "0,0")) +(rule "assignment_write_static_attribute" (formula "2") (term "1,0,0")) + (builtin "One Step Simplification" (formula "2")) +(rule "commute_and" (formula "2") (term "0")) +(rule "andRight" (formula "2")) +(branch + (rule "andRight" (formula "2")) + (branch + (rule "staticMethodCallStaticViaTypereference" (formula "2")) + (rule "methodBodyExpand" (formula "2") (newnames "heapBefore_m_C2,savedHeapBefore_m_C2")) + (builtin "One Step Simplification" (formula "2")) + (rule "methodCallEmpty" (formula "2")) + (rule "blockEmpty" (formula "2")) + (builtin "Use Operation Contract" (formula "2") (newnames "heapBefore_m_C1,exc,heapAfter_m_C1,anon_heap_m_C1") (contract "cp.C1[cp.C1::m_C1()].JML normal_behavior operation contract.0") (modality "diamond")) + (branch "Post (m_C1)" + (builtin "One Step Simplification" (formula "3")) + (rule "andLeft" (formula "3")) + (builtin "Use Operation Contract" (formula "5") (newnames "heapBefore_m_C,exc_0,heapAfter_m_C,anon_heap_m_C") (contract "cp.C[cp.C::m_C()].JML normal_behavior operation contract.0") (modality "diamond")) + (branch "Post (m_C)" + (builtin "One Step Simplification" (formula "7")) + (builtin "One Step Simplification" (formula "6")) + (rule "andLeft" (formula "6")) + (rule "emptyModality" (formula "8")) + (rule "closeTrue" (formula "8")) + ) + (branch "Exceptional Post (m_C)" + (builtin "One Step Simplification" (formula "7")) + (builtin "One Step Simplification" (formula "6")) + (rule "andLeft" (formula "6")) + (rule "andLeft" (formula "7")) + (rule "andLeft" (formula "7")) + (rule "notLeft" (formula "7")) + (rule "close" (formula "9") (ifseqformula "8")) + ) + (branch "Pre (m_C)" + (builtin "One Step Simplification" (formula "5")) + (rule "wellFormedAnonEQ" (formula "5") (ifseqformula "3")) + (rule "replace_known_left" (formula "5") (term "0") (ifseqformula "1")) + (builtin "One Step Simplification" (formula "5") (ifInst "" (formula "2"))) + (rule "closeTrue" (formula "5")) + ) + ) + (branch "Exceptional Post (m_C1)" + (builtin "One Step Simplification" (formula "3")) + (rule "andLeft" (formula "3")) + (rule "andLeft" (formula "4")) + (rule "andLeft" (formula "4")) + (rule "notLeft" (formula "4")) + (rule "close" (formula "6") (ifseqformula "5")) + ) + (branch "Pre (m_C1)" + (builtin "One Step Simplification" (formula "2") (ifInst "" (formula "1"))) + (rule "closeTrue" (formula "2")) + ) + ) + (branch + (rule "emptyModality" (formula "2") (term "1")) + (builtin "One Step Simplification" (formula "2")) + (rule "selectOfStoreSameLoc" (formula "2") (term "0")) + (builtin "One Step Simplification" (formula "2")) + (rule "castDel" (formula "2") (term "0")) + (builtin "One Step Simplification" (formula "2")) + (rule "closeTrue" (formula "2")) + ) +) +(branch + (rule "emptyModality" (formula "2") (term "1")) + (builtin "One Step Simplification" (formula "2")) + (rule "closeTrue" (formula "2")) +) +) +} From b2a6506e502d3b1edc6584c95a22ef89701b6f9e Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Mon, 20 Jul 2026 22:05:12 +0200 Subject: [PATCH 11/15] Bucket the duplicate-application veto by a label-agnostic focus fingerprint The veto that rejects a rule application already performed on the branch scans a bucket of applied applications that share the candidate's focus-term fingerprint. The fingerprint has to agree with the equality the bucket is probed with, which compares focus terms modulo irrelevant term labels: a duplicate whose focus differs only in a label (origin labels, for instance, carry where a term came from) must land in the candidate's bucket, or it escapes the veto. A not so nice caveat is that we introduce another cached hashcode. The field will only be temporary and can be removed once the normal hashcode is label agnostic PR #3884. The hash discriminator invariant of the tie-break, the agreement of its two comparators and the label blindness of both ordering hashes are pinned by a property test. with AI tooling support --- .../java/de/uka/ilkd/key/logic/TermImpl.java | 47 +++++-- .../feature/AppliedRuleAppsNameCache.java | 33 ++--- .../TieBreakComparatorPropertyTest.java | 129 ++++++++++++++++-- .../main/java/org/key_project/logic/Term.java | 6 + 4 files changed, 176 insertions(+), 39 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java index 7dc1afa095b..6a5b51c32ea 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java +++ b/key.core/src/main/java/de/uka/ilkd/key/logic/TermImpl.java @@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger; import de.uka.ilkd.key.java.ast.PositionInfo; +import de.uka.ilkd.key.logic.equality.RenamingTermProperty; import de.uka.ilkd.key.logic.label.TermLabel; import de.uka.ilkd.key.logic.op.*; @@ -104,6 +105,11 @@ class TermImpl implements JTerm { */ private int nameHash = -1; + /** + * Cached {@link #labelAgnosticHash()} value. {@code -1} = not yet computed. + */ + private int labelAgnosticHash = -1; + // ------------------------------------------------------------------------- // constructors // ------------------------------------------------------------------------- @@ -238,20 +244,25 @@ public int nameHash() { return nameHash; } + @Override + public int labelAgnosticHash() { + if (labelAgnosticHash == -1) { + computeHashes(); + } + return labelAgnosticHash; + } + /** - * Fills the caches of {@link #hashCode()} and {@link #nameHash()} together. Both hashes are - * recursions over the whole subterm tree, so a term that needs both would walk the tree - * twice; this walk visits every subterm once and fills both caches while the term is in the - * processor cache. The values are exactly those of the two separate computations: the - * hashCode part is still produced by the (subclass-overridable) {@link #computeHashCode()}, - * which finds all subterm hashes already cached. + * Computes the three hashcode caches of {@link #hashCode()}, {@link #nameHash()} and + * {@link #labelAgnosticHash()}. */ private void computeHashes() { // Iterate the subterm array, not arity(): the term factory probes hashCode() before it // validates that the operator's arity matches the subterm count, so the two can differ. final int n = subs.size(); for (int i = 0; i < n; i++) { - if (subs.get(i) instanceof TermImpl t && (t.hashcode == -1 || t.nameHash == -1)) { + if (subs.get(i) instanceof TermImpl t + && (t.hashcode == -1 || t.nameHash == -1 || t.labelAgnosticHash == -1)) { t.computeHashes(); } } @@ -270,6 +281,26 @@ private void computeHashes() { } nameHash = h; } + if (labelAgnosticHash == -1) { + // like the base computeHashCode() (op, bound vars, program, subterms) but recursing + // through labelAgnosticHash and never adding this term's labels, so it is a full, + // program-aware structural hash that ignores only term labels. It is computed here + // instead of through computeHashCode() because the LabeledTermImpl override of that + // method folds the labels in, which would make this hash label-sensitive. + // This hash can disappear and be replaced with the normal hashcode once PR 3884 is + // merged and the normal hashcode becomes label agnostic + int h = 5; + h = h * 17 + op.hashCode(); + h = h * 17 + boundVars().hashCode(); + h = h * 17 + javaBlock().hashCode(); + for (int i = 0; i < n; i++) { + h = h * 17 + subs.get(i).labelAgnosticHash(); + } + if (h == -1) { + h = 0; + } + labelAgnosticHash = h; + } } @Override @@ -505,7 +536,7 @@ public boolean containsJavaBlockRecursive() { */ public int hashCodeModRenaming() { if (hashcodeModRenaming == -1) { - final int h = de.uka.ilkd.key.logic.equality.RenamingTermProperty.RENAMING_TERM_PROPERTY + final int h = RenamingTermProperty.RENAMING_TERM_PROPERTY .hashCodeModThisProperty(this); hashcodeModRenaming = h == -1 ? 0 : h; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AppliedRuleAppsNameCache.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AppliedRuleAppsNameCache.java index 074bb2733eb..f59b8803e0c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AppliedRuleAppsNameCache.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/AppliedRuleAppsNameCache.java @@ -23,15 +23,15 @@ * See the get method for additional required constraints for correctness. *

* Within a rule name the applied apps are additionally bucketed by an application - * fingerprint ({@link #focusFingerprint}: the operators of the focus term and its direct - * subterms), or {@code 0} for find-less apps. This turns the duplicate search in + * fingerprint ({@link #focusFingerprint}: the label-agnostic structural hash of the + * focus term), or {@code 0} for find-less apps. This turns the duplicate search in * {@link AbstractNonDuplicateAppFeature} from a linear scan over all same-named applications on the * branch into a bucket lookup. It is sound for every duplicate check because each one's * {@code comparePio} implies the two focus terms are equal up to term labels: * {@link NonDuplicateAppFeature} (equal positions), {@link EqNonDuplicateAppFeature} (equal * positions modulo formula renaming) and {@link NonDuplicateAppModPositionFeature} (equal focus - * terms modulo irrelevant labels). The fingerprint is built only from operators (never from term - * labels), so focus terms that are equal up to labels always share a fingerprint, and a duplicate + * terms modulo irrelevant labels). The fingerprint ignores term labels, so focus terms that are + * equal up to labels always share a fingerprint, and a duplicate * can only ever live in the candidate's own bucket -- including for the modulo-position variant, * which deliberately matches the same focus term at different sequent positions. * @@ -53,22 +53,19 @@ public class AppliedRuleAppsNameCache { public AppliedRuleAppsNameCache() {} /** - * A cheap, label-insensitive fingerprint of a focus term for bucketing applied rule apps: the - * top operator plus the operators of its direct subterms. It is built only from operators (an - * operator is not a term label), so it is invariant under the mod-term-labels equality the - * buckets are probed with -- a duplicate therefore always shares the candidate's bucket. It is - * O(arity) and touches no subterm below depth one, unlike a full term hash. Coarser than a full - * hash (more terms may share a bucket), but the {@code sameApplication} scan resolves any - * collision, so this only trades a little bucket length for a much cheaper fingerprint. + * A cheap, label-insensitive fingerprint of a focus term for bucketing applied rule apps: + * its {@link Term#labelAgnosticHash()}. That hash folds the term's operators, bound + * variables, programs and subterms and never its term labels, so it is invariant under the + * mod-term-labels equality the buckets are probed with, and a duplicate always shares the + * candidate's bucket. The hash is cached on the term, so bucketing is exact at O(1) per + * lookup, one term per bucket up to genuine collisions, which the {@code sameApplication} + * scan resolves. It deliberately does not use {@link Term#nameHash()}: that ignores the + * program of a modality, so on update-simplification proofs, whose focus terms are + * modalities differing only in their program, it collapses everything into one bucket and + * degrades the {@code sameApplication} scan to quadratic. */ public static int focusFingerprint(Term focus) { - int h = focus.op().hashCode(); - final int arity = focus.arity(); - h = 31 * h + arity; - for (int i = 0; i < arity; i++) { - h = 31 * h + focus.sub(i).op().hashCode(); - } - return h; + return focus.labelAgnosticHash(); } /** diff --git a/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java b/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java index 1d1679e3a76..f335e369cb1 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java +++ b/key.core/src/test/java/de/uka/ilkd/key/strategy/TieBreakComparatorPropertyTest.java @@ -3,12 +3,13 @@ * SPDX-License-Identifier: GPL-2.0-only */ package de.uka.ilkd.key.strategy; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import de.uka.ilkd.key.logic.JTerm; import de.uka.ilkd.key.logic.TermFactory; +import de.uka.ilkd.key.logic.label.ParameterlessTermLabel; +import de.uka.ilkd.key.logic.label.TermLabel; import de.uka.ilkd.key.logic.op.JFunction; import de.uka.ilkd.key.logic.sort.SortImpl; @@ -16,6 +17,7 @@ import org.key_project.logic.Term; import org.key_project.logic.op.Function; import org.key_project.logic.sort.Sort; +import org.key_project.util.collection.ImmutableArray; import org.junit.jupiter.api.Test; @@ -33,19 +35,8 @@ */ public class TieBreakComparatorPropertyTest { - private static Method compareByName; - private static int cmp(Term a, Term b) { - try { - if (compareByName == null) { - compareByName = RuleAppContainer.class.getDeclaredMethod("compareByName", - Term.class, Term.class); - compareByName.setAccessible(true); - } - return (int) compareByName.invoke(null, a, b); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return RuleAppContainer.compareByName(a, b); } private static JTerm t(TermFactory tf, Function f, JTerm... subs) { @@ -122,4 +113,116 @@ void compareByNameIsStrictTotalOrderOnLabelFreeTerms() { } assertTrue(triples > 0, "test set too flat"); } + + /** + * The invariant the production comparator rests on: {@code compareFormulasByName} tries the + * cached name hash first and walks only on a hash tie, which is a total order exactly when a + * walk tie implies a hash tie. Checked over structurally equal terms built as distinct + * objects, so the identity shortcut cannot hide a violation. + */ + @Test + void walkTieImpliesNameHashTie() { + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final TermFactory tf = services.getTermFactory(); + final List terms = generatedTerms(tf); + final List copies = generatedTerms(tf); + int ties = 0; + for (int i = 0; i < terms.size(); i++) { + for (int j = 0; j < terms.size(); j++) { + final Term a = terms.get(i); + final Term b = copies.get(j); + if (cmp(a, b) == 0) { + ties++; + assertEquals(a.nameHash(), b.nameHash(), + "walk tie without hash tie for [" + a + "] vs [" + b + "]"); + } + } + } + assertTrue(ties >= terms.size(), "expected at least the diagonal ties"); + } + + /** + * The production path {@code compareFormulasByName} must order exactly like the plain walk: + * the hash is a discriminator for speed, never for a different order. A tie means a walk + * tie, and where the hashes disagree the walk of that pair is what loses, so only the sign + * consistency on hash ties can be asserted; totality and antisymmetry hold over the set. + */ + @Test + void formulaComparatorAgreesWithTheWalk() { + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final TermFactory tf = services.getTermFactory(); + final List terms = generatedTerms(tf); + final List copies = generatedTerms(tf); + for (int i = 0; i < terms.size(); i++) { + for (int j = 0; j < terms.size(); j++) { + final Term a = terms.get(i); + final Term b = copies.get(j); + final int full = RuleAppContainer.compareFormulasByName(a, b); + final int back = RuleAppContainer.compareFormulasByName(b, a); + assertEquals(Integer.signum(full), -Integer.signum(back), + "antisymmetry violated for [" + a + "] vs [" + b + "]"); + if (full == 0) { + assertEquals(0, cmp(a, b), + "formula comparator tie without walk tie for [" + a + "] vs [" + b + "]"); + } + if (a.nameHash() == b.nameHash()) { + assertEquals(Integer.signum(cmp(a, b)), Integer.signum(full), + "hash-tied pair ordered differently than the walk: [" + a + "] vs [" + + b + "]"); + } + } + } + } + + /** + * Term labels are invisible to the ordering: a labeled variant shares the name hash and the + * label-agnostic hash of the plain term and compares as a tie, although the two terms are + * not equal. + */ + @Test + void orderingHashesIgnoreLabels() { + final var services = de.uka.ilkd.key.rule.TacletForTests.services(); + final TermFactory tf = services.getTermFactory(); + final Sort s = new SortImpl(new Name("S")); + final Function a = new JFunction(new Name("a"), s); + final Function f = new JFunction(new Name("f"), s, s); + final JTerm plain = t(tf, f, t(tf, a)); + final JTerm labeled = tf.createTerm(f, new JTerm[] { t(tf, a) }, + new ImmutableArray(ParameterlessTermLabel.ANON_HEAP_LABEL)); + + assertTrue(!plain.equals(labeled), "the label must matter for equality"); + assertEquals(plain.nameHash(), labeled.nameHash(), "nameHash must ignore labels"); + assertEquals(plain.labelAgnosticHash(), labeled.labelAgnosticHash(), + "labelAgnosticHash must ignore labels"); + assertEquals(0, cmp(plain, labeled), "the walk must ignore labels"); + assertEquals(0, RuleAppContainer.compareFormulasByName(plain, labeled), + "the production comparator must ignore labels"); + } + + /** The generated term set of the total-order test, built fresh so instances are distinct. */ + private static List generatedTerms(TermFactory tf) { + final Sort s = new SortImpl(new Name("S")); + final Function a = new JFunction(new Name("a"), s); + final Function b = new JFunction(new Name("b"), s); + final Function c = new JFunction(new Name("c"), s); + final Function f = new JFunction(new Name("f"), s, s); + final Function g = new JFunction(new Name("g"), s, s, s); + final Function h = new JFunction(new Name("h"), s, s, s); + final List base = new ArrayList<>(); + base.add(t(tf, a)); + base.add(t(tf, b)); + base.add(t(tf, c)); + final List terms = new ArrayList<>(base); + for (JTerm x : base) { + terms.add(t(tf, f, x)); + for (JTerm y : base) { + terms.add(t(tf, g, x, y)); + terms.add(t(tf, h, x, y)); + terms.add(t(tf, f, t(tf, f, x))); + terms.add(t(tf, g, t(tf, f, x), y)); + terms.add(t(tf, h, x, t(tf, g, x, y))); + } + } + return terms; + } } diff --git a/key.ncore/src/main/java/org/key_project/logic/Term.java b/key.ncore/src/main/java/org/key_project/logic/Term.java index 7e2d6641629..c350bdf8784 100644 --- a/key.ncore/src/main/java/org/key_project/logic/Term.java +++ b/key.ncore/src/main/java/org/key_project/logic/Term.java @@ -52,6 +52,12 @@ public interface Term extends LogicElement, Sorted { /// differ. int nameHash(); + /// A hash folded from the operators, arities, bound variables, programs (Java blocks) and + /// subterm structure of this term, ignoring only term labels. Unlike [#nameHash()] it + /// distinguishes modalities by their program; unlike [#hashCode()] it ignores term labels, so + /// it is the same in every run. Terms equal up to labels share it. Cached. + int labelAgnosticHash(); + /// Returns a serial number for a term. The serial number is not persistent. int serialNumber(); From 904ff2215d2043a54f6663ec0031ba9486faa7f1 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Mon, 20 Jul 2026 22:05:13 +0200 Subject: [PATCH 12/15] Thread-local per worker caches for the one-step simplifier This reduces the locking overhead for single core and also multi-threaded proving significantly. Contrary to intuition the loss of cache sharing between goals (and workers) does not hurt performance, but improves it. --- .../uka/ilkd/key/rule/OneStepSimplifier.java | 90 ++++++++++++++----- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java b/key.core/src/main/java/de/uka/ilkd/key/rule/OneStepSimplifier.java index aef7e5c94a6..1d58f47ee7e 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 @@ -37,7 +37,6 @@ import org.key_project.prover.rules.instantiation.AssumesFormulaInstDirect; import org.key_project.prover.rules.instantiation.AssumesFormulaInstantiation; import org.key_project.prover.sequent.*; -import org.key_project.util.StripedLruCache; import org.key_project.util.collection.ImmutableArray; import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.Immutables; @@ -59,10 +58,6 @@ public final class OneStepSimplifier implements BuiltInRule { private static final int APPLICABILITY_CACHE_SIZE = 1000; private static final int DEFAULT_CACHE_SIZE = 10000; - /** - * Lock stripes for the OSS caches; OSS runs concurrently on every worker, so split the lock. - */ - private static final int OSS_CACHE_STRIPES = 16; /** * Represents a list of rule applications performed in one OSS step. @@ -71,6 +66,28 @@ public static final class Protocol extends ArrayList { private static final long serialVersionUID = 8788009073806993077L; } + /** + * A bounded, access-ordered LRU map for use by a single thread only. It is deliberately not + * synchronised: each worker holds its own instance through a {@link ThreadLocal}, so no two + * threads ever touch the same map and no lock is needed. Eviction order is irrelevant because + * the cached value is a pure function of the key. + * It is an inner class to prevent reuse in thread-unsafe contexts. + */ + private static final class LRU extends LinkedHashMap { + private static final long serialVersionUID = 1L; + private final int maxEntries; + + LRU(int maxEntries) { + super(maxEntries + 1, 1.0F, true); + this.maxEntries = maxEntries; + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > maxEntries; + } + } + private static final Name NAME = new Name("One Step Simplification"); /** @@ -86,13 +103,19 @@ public static final class Protocol extends ArrayList { private static final boolean[] bottomUp = { false, false, false, false, true, true, true, false }; - // OSS is shared per proof and runs concurrently on every parallel-prover worker. Its two caches - // are PURE (the value is a function of the key: "does this formula simplify?" / "this term is - // irreducible"), so eviction order is irrelevant to the result and a striped (lower-contention) - // cache is sound. They are therefore the only state the hot path (isApplicable/apply) touches - // besides the goal it owns, so that path needs no lock. - private final StripedLruCache applicabilityCache = - new StripedLruCache<>(APPLICABILITY_CACHE_SIZE, OSS_CACHE_STRIPES); + + /** + * Applicability cache that is lock-free. Lock-freeness is achieved by using thread-local caches + * which + * keeps the wrapped unsynchronized (and by itself thread unsafe cache) thread-safe. + * The reduction of locking improves performance for OSS heavy proofs by up-to 20% in + * single-core + * and multi-core. The multi-core case looses the cache sharing among goals but this + * disadvantage + * is more than equalized by removing locking. + */ + private volatile ThreadLocal> applicabilityCache = + newApplicabilityCache(); /** * Guards the (re)build/teardown of the per-proof state below (refresh/initIndices/ @@ -106,7 +129,9 @@ public static final class Protocol extends ArrayList { private Proof lastProof; private ImmutableList appsTakenOver; private volatile TacletIndex[] indices; - private volatile StripedLruCache[] notSimplifiableCaches; + // The per-worker "irreducible term" cache (one LRU per rule set); same goal-independence and + // swap-on-proof-change rationale as applicabilityCache above. + private volatile ThreadLocal[]> notSimplifiableCaches; private volatile boolean active; // ------------------------------------------------------------------------- @@ -195,32 +220,46 @@ private ImmutableList tacletsForRuleSet(Proof proof, String ruleSetName, } + /** A fresh, empty per-worker applicability cache (one {@link LRU} map per worker thread). */ + private static ThreadLocal> newApplicabilityCache() { + return ThreadLocal.withInitial(() -> new LRU<>(APPLICABILITY_CACHE_SIZE)); + } + + /** A fresh, empty per-worker not-simplifiable cache (one {@link LRU} map per rule set). */ + @SuppressWarnings("unchecked") + private static ThreadLocal[]> newNotSimplifiableCaches() { + return ThreadLocal.withInitial(() -> { + final LRU[] caches = (LRU[]) new LRU[ruleSets.size()]; + for (int i = 0; i < caches.length; i++) { + caches[i] = new LRU<>(DEFAULT_CACHE_SIZE); + } + return caches; + }); + } + /** * If the rule is applied to a different proof than last time, then clear all caches and * initialise the taclet indices. */ - @SuppressWarnings("unchecked") private void initIndices(Proof proof) { if (proof != lastProof) { shutdownIndices(); lastProof = proof; appsTakenOver = ImmutableList.nil(); - // Build into locals, then publish to the volatile fields in one write each, so a + // Build into a local, then publish to the volatile field in one write, so a // (hypothetical) concurrent reader never sees a half-filled array. final TacletIndex[] newIndices = new TacletIndex[ruleSets.size()]; - final StripedLruCache[] newCaches = - (StripedLruCache[]) new StripedLruCache[newIndices.length]; int i = 0; ImmutableList done = ImmutableList.nil(); for (String ruleSet : ruleSets) { ImmutableList taclets = tacletsForRuleSet(proof, ruleSet, done); newIndices[i] = TacletIndexKit.getKit().createTacletIndex(taclets); - newCaches[i] = new StripedLruCache<>(DEFAULT_CACHE_SIZE, OSS_CACHE_STRIPES); i++; done = done.prepend(ruleSet); } indices = newIndices; - notSimplifiableCaches = newCaches; + // Install fresh per-worker maps for the new proof; the previous ThreadLocal is dropped. + notSimplifiableCaches = newNotSimplifiableCaches(); } } @@ -242,7 +281,8 @@ public void shutdownIndices() { g.ruleAppIndex().clearIndexes(); } } - applicabilityCache.clear(); + // Drop every worker's applicability map by installing a fresh ThreadLocal. + applicabilityCache = newApplicabilityCache(); lastProof = null; appsTakenOver = null; indices = null; @@ -325,7 +365,8 @@ private SequentFormula simplifyPosOrSub(Goal goal, PosInOccurrence pos, int indexNr, Protocol protocol) { final JTerm term = (JTerm) pos.subTerm(); - if (notSimplifiableCaches[indexNr].get(term) != null) { + final LRU cache = notSimplifiableCaches.get()[indexNr]; + if (cache.get(term) != null) { return null; } @@ -343,7 +384,7 @@ private SequentFormula simplifyPosOrSub(Goal goal, } if (result == null) { - notSimplifiableCaches[indexNr].put(term, term); + cache.put(term, term); } return result; @@ -545,7 +586,8 @@ private Instantiation computeInstantiation(PosInOccurrence ossPIO, private boolean applicableTo(Services services, SequentFormula cf, boolean inAntecedent, Goal goal, RuleApp ruleApp) { - final Boolean b = applicabilityCache.get(cf); + final LRU cache = applicabilityCache.get(); + final Boolean b = cache.get(cf); if (b != null) { return b; } else { @@ -554,7 +596,7 @@ private boolean applicableTo(Services services, simplifyConstrainedFormula(cf, inAntecedent, null, null, null, goal, ruleApp); final boolean result = simplifiedCf != null && !simplifiedCf.equals(cf); - applicabilityCache.put(cf, result); + cache.put(cf, result); return result; } } From 5d3638e92a550974a7849d4ebbeda3d514187a0b Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Tue, 21 Jul 2026 12:43:37 +0200 Subject: [PATCH 13/15] Bound DefOps cross-multiplication in degree and per branch --- .../ilkd/key/strategy/IntegerStrategy.java | 155 +++++++++--------- .../BranchMultiplicationCountFeature.java | 114 +++++++++++++ 2 files changed, 192 insertions(+), 77 deletions(-) create mode 100644 key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java index 67975a44bb2..4896a823ea5 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/IntegerStrategy.java @@ -26,7 +26,6 @@ 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.CostLocality; import org.key_project.prover.strategy.costbased.MutableState; import org.key_project.prover.strategy.costbased.RuleAppCost; import org.key_project.prover.strategy.costbased.TopRuleAppCost; @@ -48,10 +47,19 @@ /// Do not create directly, instead use [IntegerStrategyFactory]. public class IntegerStrategy extends AbstractFeatureStrategy implements ComponentStrategy { + /// Reads better than a bare boolean at the call sites of [#setupMultiplyInequations]. + private static final boolean AT_APPROVAL = true; + private static final boolean AT_COST = false; + public static final Name NAME = new Name("Integer Strategy"); /// Magic constants private static final int IN_EQ_SIMP_NON_LIN_COST = 1000; + + /// Caps how often a cross multiplication is applied on a branch. + /// Justified by empirical measurements. Candidate to be exposed in + /// a settings strategy pane (not the strategy pane) + private static final int BRANCH_MULT_CAP = 8; private static final int POLY_DIVISION_COST = -2250; /// The features defining the three phases: cost computation, approval, @@ -64,9 +72,20 @@ public class IntegerStrategy extends AbstractFeatureStrategy implements Componen private final ArithTermFeatures tf; private final FormulaTermFeatures ff; + /// enum for the different arithmetic treatments + private enum ArithTreatment { + /// Non-linear arithmetic switched off. + BASIC, + /// Inequations are cross-multiplied but only in a bound and capped manner. + /// Division and modulo are expanded by their defining axioms. + DEF_OPS, + /// Cross-multiplication is admitted more freely, and equation splitting, case + /// distinctions and cuts are added on top. + MODEL_SEARCH + } + /// configuration options extracted from [StrategyProperties] - private final boolean nonLinearArithmeticEnabled; - private final boolean divAndModuloReasoningEnabled; + private final ArithTreatment arith; private final boolean stopAtFirstNonCloseableGoal; public IntegerStrategy(Proof proof, StrategyProperties strategyProperties) { @@ -75,12 +94,15 @@ public IntegerStrategy(Proof proof, StrategyProperties strategyProperties) { 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)); + final String nonLinArith = + strategyProperties.getProperty(StrategyProperties.NON_LIN_ARITH_OPTIONS_KEY); + if (StrategyProperties.NON_LIN_ARITH_COMPLETION.equals(nonLinArith)) { + arith = ArithTreatment.MODEL_SEARCH; + } else if (StrategyProperties.NON_LIN_ARITH_DEF_OPS.equals(nonLinArith)) { + arith = ArithTreatment.DEF_OPS; + } else { + arith = ArithTreatment.BASIC; + } stopAtFirstNonCloseableGoal = strategyProperties.getProperty(StrategyProperties.STOPMODE_OPTIONS_KEY) @@ -115,7 +137,7 @@ private RuleSetDispatchFeature setupInstantiationF() { // cost; Basic keeps them uninstantiated at infinity. Model Search stays // byte-identical because this reproduces the value inEqSimp_nonLin gave it. bindRuleSet(d, "inEqSimp_nonLin_multiply", - arithNonLinInferences() || arithDefOps() ? longConst(IN_EQ_SIMP_NON_LIN_COST) + arith != ArithTreatment.BASIC ? longConst(IN_EQ_SIMP_NON_LIN_COST) : inftyConst()); disableInstantiate(); @@ -126,17 +148,19 @@ private RuleSetDispatchFeature setupApprovalDispatcher() { final RuleSetDispatchFeature d = new RuleSetDispatchFeature(); final IntegerLDT numbers = getServices().getTypeConverter().getIntegerLDT(); - if (arithNonLinInferences() || arithDefOps()) { - // The InEquationMultFeature bounding enforced here is what prevents - // cross-multiplication from running in circles: only products that are - // bounded by the left side of an inequation already present in the - // sequent are approved, so the derivable monomials are capped. In - // DefOps mode the check is stricter (exact match only) to avoid the - // saturation blow-up acceptable for Model Search. + if (arith != ArithTreatment.BASIC) { + // Two things keep cross-multiplication from running in circles. The + // InEquationMultFeature bounding admits only products bounded by the left side + // of an inequation already in the sequent, which caps the monomials that are + // derivable at all. In DefOps mode that check is stricter, exact match only, + // and a further limit applies: a branch that already carries BRANCH_MULT_CAP + // multiplications takes no more. Both are enforced here rather than where costs + // are computed, because a candidate's cost is computed when it enters the queue + // while the sequent and the branch keep growing until it is applied. // baseCost is zero on the approval dispatcher: approval only distinguishes // finite (approved) from infinite (rejected), so the base cost is irrelevant // here and left out to keep the approval decision identical to stock. - setupMultiplyInequations(d, longConst(0), inftyConst(), !arithNonLinInferences()); + setupMultiplyInequations(d, longConst(0), inftyConst(), AT_APPROVAL); } // these taclets are not supposed to be applied with metavariable // instantiations @@ -160,7 +184,7 @@ private RuleSetDispatchFeature setupApprovalDispatcher() { bindRuleSet(d, "defOps_div", NonDuplicateAppModPositionFeature.INSTANCE); bindRuleSet(d, "defOps_jdiv", NonDuplicateAppModPositionFeature.INSTANCE); - if (arithNonLinInferences()) { + if (arith == ArithTreatment.MODEL_SEARCH) { setupInEqCaseDistinctionsApproval(d); } @@ -227,14 +251,6 @@ private RuleSetDispatchFeature setupCostComputationF() { return d; } - private boolean arithNonLinInferences() { - return nonLinearArithmeticEnabled; - } - - private boolean arithDefOps() { - return divAndModuloReasoningEnabled; - } - @Override public boolean isStopAtFirstNonCloseableGoal() { return stopAtFirstNonCloseableGoal; @@ -272,19 +288,12 @@ private void setupArithPrimaryCategories(RuleSetDispatchFeature d) { bindRuleSet(d, "inEqSimp_forNormalisation", -1100); bindRuleSet(d, "inEqSimp_special_nonLin", -1400); - if (arithNonLinInferences()) { + if (arith == ArithTreatment.MODEL_SEARCH) { bindRuleSet(d, "inEqSimp_nonLin", IN_EQ_SIMP_NON_LIN_COST); } else { bindRuleSet(d, "inEqSimp_nonLin", inftyConst()); } - // Cross-multiplication of inequations is now driven exclusively through the - // inEqSimp_nonLin_multiply rule set (the multiply_2_inEq* taclets no longer - // carry inEqSimp_nonLin). This keeps inEqSimp_nonLin at its stock cost so that - // splitEquationSucc and DefOps proofs that never cross-multiply stay on their - // stock search path. See setupInEqSimp for the per-mode binding. - // polynomial division, simplification of fractions and mods bindRuleSet(d, "polyDivision", POLY_DIVISION_COST); - } private void setupPolySimp(RuleSetDispatchFeature d, IntegerLDT numbers) { @@ -599,35 +608,22 @@ private void setupInEqSimp(RuleSetDispatchFeature d, IntegerLDT numbers) { // category "handling of non-linear inequations" - if (arithNonLinInferences()) { - setupMultiplyInequations(d, longConst(IN_EQ_SIMP_NON_LIN_COST), longConst(100), false); + if (arith == ArithTreatment.MODEL_SEARCH) { + setupMultiplyInequations(d, longConst(IN_EQ_SIMP_NON_LIN_COST), longConst(100), + AT_COST); bindRuleSet(d, "inEqSimp_split_eq", add(TopLevelFindFeature.SUCC, longConst(-100))); bindRuleSet(d, "inEqSimp_signCases", not(isInstantiated("signCasesLeft"))); - } else if (arithDefOps()) { + } else if (arith == ArithTreatment.DEF_OPS) { // DefOps also cross-multiplies inequations, but - unlike Model Search - does // no equation splitting, case distinctions or cuts, and only multiplies when // the product exactly matches the left side of an inequation already in the - // sequent (onlyExactlyBounded, enforced at approval). This terminates: the - // monomial ordering is degree-graded, so products (which equal an existing - // left side) and all monomials of the resulting right side stay within the - // degree of the existing left sides - a finite monomial universe. DefOps - // proofs without integer inequations enqueue no multiply candidates and keep - // their stock search path. - // - // Note: inEqSimp_split_eq and inEqSimp_signCases are deliberately NOT bound - // here. Since the multiply_2_inEq* taclets no longer carry inEqSimp_nonLin, - // that rule set keeps its stock (infinite) DefOps cost, which already switches - // splitEquationSucc off exactly as in stock DefOps. - // - // notAllowed is finite (not infinity): an app whose \assumes is not yet matched - // takes this branch, and needs a finite cost to survive long enough for the - // assumes-completion machinery to match it and re-evaluate as exactly bounded. - // Non-exactly-bounded apps are ultimately rejected by the approval dispatcher. - // The value matches the Model Search convention above; raising it does not - // measurably reduce the (inherent) reordering of arithmetic proofs. - setupMultiplyInequations(d, longConst(IN_EQ_SIMP_NON_LIN_COST), longConst(100), true); + // sequent, which the approval dispatcher enforces. DefOps proofs without + // integer inequations enqueue no multiply candidates and keep their stock + // search path. + setupMultiplyInequations(d, longConst(IN_EQ_SIMP_NON_LIN_COST), longConst(100), + AT_COST); } else { // Basic arithmetic: cross-multiplication is off. inEqSimp_nonLin used to be // the off-switch via the (now removed) tag on the multiply taclets, so the @@ -673,12 +669,6 @@ public void setContent(Term term, MutableState mState) {} return tOne; } - @Override - public CostLocality locality() { - // a constant term fixed at strategy construction: annotations are looked up on - // the concrete (here: anonymous) class, so the classification is given explicitly - return CostLocality.STABLE; - } }; final JTerm tTwo = getServices().getTermBuilder().zTerm("2"); @@ -697,12 +687,6 @@ public void setContent(Term term, MutableState mState) {} return tTwo; } - @Override - public CostLocality locality() { - // a constant term fixed at strategy construction: annotations are looked up on - // the concrete (here: anonymous) class, so the classification is given explicitly - return CostLocality.STABLE; - } }; bindRuleSet(d, "inEqSimp_or_tautInEqs", @@ -747,14 +731,21 @@ public CostLocality locality() { * rule set); zero for the approval dispatcher, {@link #IN_EQ_SIMP_NON_LIN_COST} for * the cost dispatcher * @param notAllowedF the costs in case the multiplication is not allowed - * @param onlyExactlyBounded if true, only products that exactly match the left side of - * an inequation already present in the sequent are allowed (used in DefOps mode: - * multiplication strictly directed at existing goal monomials); if false, products - * that are merely subsumed by an existing left side are admitted as well (Model - * Search: more speculative saturation) + * @param atApproval whether the features are bound to the approval dispatcher, which is the + * only place a limit can be enforced that depends on how far the proof has come: a + * candidate's cost is computed when it enters the queue, while the sequent and the + * branch keep growing until it is applied */ private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature baseCost, - Feature notAllowedF, boolean onlyExactlyBounded) { + Feature notAllowedF, boolean atApproval) { + // In DefOps a product is admitted only when it exactly matches the left side of an + // inequation already in the sequent, so multiplication stays directed at monomials the + // proof is asking about. Model Search also admits products merely subsumed by such a + // left side, and saturates more speculatively. + final boolean onlyExactlyBounded = arith == ArithTreatment.DEF_OPS; + // The branch limit exists to stop DefOps saturating; Model Search is expected to + // saturate and keeps its unlimited behaviour. + final boolean capBranch = atApproval && arith == ArithTreatment.DEF_OPS; final TermBuffer intRel = new TermBuffer(); /* @@ -799,6 +790,16 @@ private void setupMultiplyInequations(RuleSetDispatchFeature d, Feature baseCost */ not(TermSmallerThanFeature.create(FocusProjection.create(0), AssumptionProjection.create(0))), + onlyExactlyBounded + ? ifZero(add(applyTF("multLeft", tf.linearMonomial), + applyTF("multFacLeft", tf.linearMonomial)), longConst(0), + notAllowedF) + : longConst(0), + + capBranch + ? ifZero(BranchMultiplicationCountFeature.atMost("multiply_2_inEq", + BRANCH_MULT_CAP), longConst(0), notAllowedF) + : longConst(0), ifZero(exactlyBounded, longConst(0), onlyExactlyBounded ? notAllowedF : ifZero(totallyBounded, longConst(100), notAllowedF)) @@ -819,7 +820,7 @@ private void setupInEqSimpInstantiation(RuleSetDispatchFeature d) { setupSquaresAreNonNegative(d); - if (arithNonLinInferences()) { + if (arith == ArithTreatment.MODEL_SEARCH) { setupInEqCaseDistinctions(d); } } @@ -1008,7 +1009,7 @@ private void setupInEqCaseDistinctionsApproval(RuleSetDispatchFeature d) { private void setupDefOpsPrimaryCategories(RuleSetDispatchFeature d) { - if (arithDefOps()) { + if (arith != ArithTreatment.BASIC) { // the axiom defining division only has to be inserted once, because // it adds equations to the antecedent bindRuleSet(d, "defOps_div", diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java new file mode 100644 index 00000000000..ca8305230e7 --- /dev/null +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java @@ -0,0 +1,114 @@ +/* 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.feature; + +import de.uka.ilkd.key.proof.Goal; +import de.uka.ilkd.key.proof.Node; +import de.uka.ilkd.key.rule.TacletApp; +import de.uka.ilkd.key.util.properties.Properties.Property; + +import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.strategy.costbased.MutableState; +import org.key_project.prover.strategy.costbased.feature.Feature; + +/** + * Counts how often a rule has already been applied on the branch leading to a goal, and admits a + * further application only while that count stays within a limit. + * + *

+ * A single application says nothing about whether a proof is saturating: the first one on a branch + * and the twentieth look alike, so a criterion that describes only the application cannot tell them + * apart. The branch it sits on does. On the Stipula bike obligation, which needs + * cross-multiplication to close, no branch reaches six applications; on the deposit obligation, + * where the rule saturates, the median application is the nineteenth on its branch. + *

+ * + *

+ * The count is carried in the goal's strategy information rather than recomputed or held in a map. + * A goal inherits the count of the node it grew from, so advancing costs one comparison, and + * pruning restores the previous value through the undo method. A map keyed by node would instead + * keep an entry for every node the proof ever had, which matters because macros such as the auto + * pilot prune heavily. + *

+ */ +public final class BranchMultiplicationCountFeature extends BinaryTacletAppFeature { + + /** + * The count as computed for one node. The serial number records which node that was, so a goal + * that has since advanced can account for the steps in between. Serial numbers are used rather + * than the nodes themselves so that nothing here keeps a pruned node, and with it a sequent, + * reachable. + * + * @param nodeSerial the node the count was computed for + * @param count applications carried by the branch strictly above that node + */ + private record BranchCount(int nodeSerial, int count) { + } + + private static final Property COUNT_ON_BRANCH = + new Property<>(BranchCount.class, "crossMultiplicationsOnBranch"); + + + private final String rulePrefix; + private final int maxOnBranch; + + /** + * Zero iff the branch leading to this goal carries at most {@code maxOnBranch} applications of + * a rule whose name starts with {@code rulePrefix}. + * + * @param rulePrefix the name prefix identifying the rules to count + * @param maxOnBranch the largest admitted number of earlier applications + * @return the feature + */ + public static Feature atMost(String rulePrefix, int maxOnBranch) { + return new BranchMultiplicationCountFeature(rulePrefix, maxOnBranch); + } + + private BranchMultiplicationCountFeature(String rulePrefix, int maxOnBranch) { + this.rulePrefix = rulePrefix; + this.maxOnBranch = maxOnBranch; + } + + private boolean appliedHere(Node node) { + final var applied = node.getAppliedRuleApp(); + return applied != null && applied.rule().name().toString().startsWith(rulePrefix); + } + + /** + * The applications carried by the branch strictly above the goal's node. Only the rules its + * proper ancestors applied are counted: a goal has not applied one yet, so counting the node + * itself would give a number every later goal on the branch inherits as one too small. + */ + private int countFor(Goal goal) { + final Node node = goal.node(); + final BranchCount known = goal.getStrategyInfo(COUNT_ON_BRANCH); + if (known != null && known.nodeSerial() == node.serialNr()) { + return known.count(); + } + + // Walk back to the node the inherited count belongs to, or to the root when there is none + // to build on. That is one step in the common case, a goal having advanced by one node. + int since = 0; + Node walk = node; + while (walk != null && (known == null || walk.serialNr() != known.nodeSerial())) { + final Node parent = walk.parent(); + if (parent != null && appliedHere(parent)) { + since++; + } + walk = parent; + } + // Reaching the root without meeting the remembered node means the count cannot be built on + // it, and the walk has already counted the whole branch. + final int total = (walk == null ? 0 : known.count()) + since; + + goal.addStrategyInfo(COUNT_ON_BRANCH, new BranchCount(node.serialNr(), total), + strategyInfos -> strategyInfos.put(COUNT_ON_BRANCH, known)); + return total; + } + + @Override + protected boolean filter(TacletApp app, PosInOccurrence pos, Goal goal, MutableState mState) { + return countFor(goal) <= maxOnBranch; + } +} From 71ced6784708a164d81643e093aed62878a71699 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Tue, 21 Jul 2026 09:01:34 +0200 Subject: [PATCH 14/15] Fix a FM tutorial proof script as we close it now automatically with autopilot only and a saved proof --- .../ArrayList/ArrayList_add.proof | 3 - .../ArrayList/LinkedList_newNode.proof | 4266 ++++++++++------- 2 files changed, 2528 insertions(+), 1741 deletions(-) diff --git a/key.ui/examples/heap/FM2024Tutorial/ArrayList/ArrayList_add.proof b/key.ui/examples/heap/FM2024Tutorial/ArrayList/ArrayList_add.proof index 4813b327015..57a4859dfe4 100644 --- a/key.ui/examples/heap/FM2024Tutorial/ArrayList/ArrayList_add.proof +++ b/key.ui/examples/heap/FM2024Tutorial/ArrayList/ArrayList_add.proof @@ -88,7 +88,4 @@ \proofScript { macro autopilot; - rule Class_invariant_axiom_for_ArrayList occ=1; - macro "split-prop"; - auto all=true steps=10000; } \ No newline at end of file diff --git a/key.ui/examples/heap/FM2024Tutorial/ArrayList/LinkedList_newNode.proof b/key.ui/examples/heap/FM2024Tutorial/ArrayList/LinkedList_newNode.proof index 7f968f9a06f..db20cc13bc9 100644 --- a/key.ui/examples/heap/FM2024Tutorial/ArrayList/LinkedList_newNode.proof +++ b/key.ui/examples/heap/FM2024Tutorial/ArrayList/LinkedList_newNode.proof @@ -68,6 +68,7 @@ "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_BEST", "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", @@ -89,8 +90,9 @@ \proof { (keyLog "0" (keyUser "mattias" ) (keyVersion "4911758ba07017f4af60dc0314ac665c14a542d0")) +(keyLog "1" (keyUser "bubel" ) (keyVersion "1167877b80956325bccf16052c6a34edc6d00911")) -(autoModeTime "25355") +(autoModeTime "26447") (branch "dummy ID" (builtin "One Step Simplification" (formula "1") (newnames "heapAtPre,o_0,f")) @@ -162,8 +164,8 @@ (rule "methodCallEmpty" (formula "10") (term "1")) (rule "blockEmpty" (formula "10") (term "1")) (rule "methodCallSuper" (formula "10") (term "1")) -(rule "methodBodyExpand" (formula "10") (term "1")) -(builtin "One Step Simplification" (formula "10")) +(rule "methodBodyExpand" (formula "10") (term "1") (newnames "heapBefore_$init,savedHeapBefore_$init")) + (builtin "One Step Simplification" (formula "10")) (rule "methodCallEmpty" (formula "10") (term "1")) (rule "methodCallEmpty" (formula "10") (term "1")) (rule "blockEmpty" (formula "10") (term "1")) @@ -186,22 +188,22 @@ (rule "andRight" (formula "10")) (branch "Case 1" (rule "andRight" (formula "10")) - (branch + (branch "Case 1" (rule "andRight" (formula "10")) - (branch + (branch "Case 1" (builtin "One Step Simplification" (formula "10") (ifInst "" (formula "7"))) (rule "closeTrue" (formula "10")) ) - (branch + (branch "Case 2" (builtin "One Step Simplification" (formula "10") (ifInst "" (formula "8"))) (rule "closeTrue" (formula "10")) ) ) (branch "Case 2" (rule "andRight" (formula "10")) - (branch + (branch "Case 1" (builtin "One Step Simplification" (formula "10")) - (rule "pullOutSelect" (formula "10") (term "0") (inst "selectSK=Node_data_0")) + (rule "pullOutSelect" (formula "10") (term "0") (inst "selectSK=Node_data_0:int")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "0")) @@ -211,23 +213,19 @@ ) (branch "Case 2" (rule "andRight" (formula "10")) - (branch + (branch "Case 1" + (builtin "One Step Simplification" (formula "10")) + (rule "selectOfStoreSameLoc" (formula "10") (term "0")) + (builtin "One Step Simplification" (formula "10")) + (rule "castDel" (formula "10") (term "0")) (builtin "One Step Simplification" (formula "10")) - (rule "dismissNonSelectedField" (formula "10") (term "0")) - (rule "dismissNonSelectedField" (formula "10") (term "0")) - (rule "pullOutSelect" (formula "10") (term "0") (inst "selectSK=Node_next_0")) - (rule "simplifySelectOfStore" (formula "1")) - (builtin "One Step Simplification" (formula "1")) - (rule "castDel" (formula "1") (term "0")) - (rule "applyEqReverse" (formula "11") (term "0") (ifseqformula "1")) - (builtin "One Step Simplification" (formula "11")) - (rule "closeTrue" (formula "11")) + (rule "closeTrue" (formula "10")) ) (branch "Case 2" (rule "andRight" (formula "10")) (branch "Case 1" (builtin "One Step Simplification" (formula "10")) - (builtin "Use Dependency Contract" (formula "10") (ifInst "" (formula "6")) (contract "LinkedList[java.lang.Object::$inv()].JML accessible clause.0") (userinteraction)) + (builtin "Use Dependency Contract" (formula "10") (ifInst "" (formula "6")) (contract "LinkedList[java.lang.Object::$inv()].JML accessible clause.0")) (rule "impLeft" (formula "7") (userinteraction)) (branch "Case 1" (rule "andRight" (formula "7")) @@ -241,13 +239,13 @@ (rule "notRight" (formula "7")) (rule "close" (formula "10") (ifseqformula "1")) ) - (branch + (branch "Case 2" (rule "close" (formula "7") (ifseqformula "3")) ) ) (branch "Case 2" (rule "andRight" (formula "7")) - (branch + (branch "Case 1" (rule "close" (formula "7") (ifseqformula "2")) ) (branch "Case 2" @@ -260,12 +258,12 @@ ) ) ) - (branch + (branch "Case 2" (rule "close" (formula "7") (ifseqformula "6")) ) ) (branch "Case 2" - (rule "Class_invariant_axiom_for_LinkedList" (formula "6") (inst "i=i") (inst "j=j") (inst "i_0=i_0") (ifseqformula "10") (userinteraction)) + (rule "Class_invariant_axiom_for_LinkedList" (formula "6") (inst "i=i") (inst "i_0=i_0") (inst "j=j") (ifseqformula "10") (userinteraction)) (rule "andLeft" (formula "6")) (rule "andLeft" (formula "6")) (rule "andLeft" (formula "8")) @@ -273,9 +271,9 @@ (rule "andLeft" (formula "6")) (rule "andLeft" (formula "6")) (rule "andLeft" (formula "6")) - (rule "disjointToElementOf" (formula "14") (inst "ov=ov") (inst "fv=fv") (userinteraction)) - (rule "allRight" (formula "14") (inst "sk=ov_0") (userinteraction)) - (rule "allRight" (formula "14") (inst "sk=fv_0") (userinteraction)) + (rule "disjointToElementOf" (formula "14") (inst "fv=fv") (inst "ov=ov") (userinteraction)) + (rule "allRight" (formula "14") (inst "sk=ov_0:java.lang.Object") (userinteraction)) + (rule "allRight" (formula "14") (inst "sk=fv_0:Field") (userinteraction)) (rule "orRight" (formula "14") (userinteraction)) (rule "notRight" (formula "15") (userinteraction)) (rule "notRight" (formula "15") (userinteraction)) @@ -340,17 +338,18 @@ ) (branch "(ov_0, fv_0) in infiniteUnion{int i_0;}(if ( inInt(i_0) & ( 0 <= i_0 & i_0 < self.size)) then ((Node)(self.nodeseq[i_0]).*) else ({}))" (rule "elementOfInfiniteUnion" (formula "3") (userinteraction)) - (rule "exLeft" (formula "3") (inst "sk=i_0_0") (userinteraction)) + (rule "exLeft" (formula "3") (inst "sk=i_0_0:int") (userinteraction)) (rule "ifthenelse_split" (formula "3") (term "2") (userinteraction)) (branch "inInt(i_0_0) & (0 <= i_0_0 & i_0_0 < self.size) TRUE" - (builtin "One Step Simplification" (formula "4") (userinteraction)) - (rule "int_induction" (inst "b=( lt(nv, select<[int]>(heap, self, LinkedList::#size))<> + (builtin "One Step Simplification" (formula "4")) + (rule "int_induction" (inst "b=( lt(nv, + select<[int]>(heap, self, LinkedList::#size))<> -> ( select<[boolean]>(heap, - (Node)(seqGet<[any]>(select<[Seq]>(heap, - self, - LinkedList::#nodeseq), - nv)), - java.lang.Object::#$created) + cast<[Node]>(seqGet<[any]>(select<[Seq]>(heap, + self, + LinkedList::#nodeseq), + nv)), + java.lang.Object::#$created) = TRUE)<>)<>") (inst "nv=nv") (userinteraction)) (branch "Base Case" (rule "impRight" (formula "18") (userinteraction)) @@ -417,7 +416,7 @@ ) (branch "self.size = 0 FALSE" (rule "applyEqReverse" (formula "20") (term "1,0") (ifseqformula "15") (userinteraction)) - (rule "eqTermCut" (formula "20") (term "1,0") (inst "s=null") (userinteraction)) + (rule "eqTermCut" (formula "20") (term "1,0") (inst "s=null:Null") (userinteraction)) (branch "Assume self.first = null" (rule "instAll" (formula "16") (term "1,0,1") (ifseqformula "15") (userinteraction)) (rule "impLeft" (formula "16") (userinteraction)) @@ -530,7 +529,7 @@ (builtin "One Step Simplification" (formula "3")) (builtin "One Step Simplification" (formula "2") (ifInst "" (formula "1")) (ifInst "" (formula "1"))) (rule "andLeft" (formula "3")) - (rule "allRight" (formula "19") (inst "sk=nv_0")) + (rule "allRight" (formula "19") (inst "sk=nv_0:int")) (rule "impRight" (formula "19")) (rule "andLeft" (formula "1")) (rule "impRight" (formula "21")) @@ -672,7 +671,7 @@ (rule "polySimp_elimOne" (formula "15") (term "1,1,0,0,1,0,1,0")) (rule "nnf_imp2or" (formula "15") (term "1,0,1,0,1,0")) (rule "commute_or" (formula "5") (term "1")) - (rule "Class_invariant_axiom_for_LinkedList" (formula "24") (inst "i=i") (inst "j=j") (inst "i_0=i_0") (ifseqformula "23")) + (rule "Class_invariant_axiom_for_LinkedList" (formula "24") (inst "i=i") (inst "i_0=i_0") (inst "j=j") (ifseqformula "23")) (builtin "One Step Simplification" (formula "24")) (rule "eqSymm" (formula "24") (term "1,0,0,1,0,1,0,0,0")) (rule "eqSymm" (formula "24") (term "1,1,0,1,0,1,0,1,0,0,0")) @@ -690,217 +689,135 @@ (rule "polySimp_addComm0" (formula "24") (term "1,0,2,0,1,1,0,1,0,0,0")) (rule "polySimp_addComm0" (formula "24") (term "1,0,0,1,1,0,1,0,0,0")) (rule "polySimp_addComm0" (formula "24") (term "1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,0,0")) + (rule "subsetSingletonLeft" (formula "24") (term "0,0,0,0,0,0")) (rule "subsetSingletonLeft" (formula "24") (term "1,0,0,0,0,0")) + (rule "castedGetAny" (formula "24") (term "0,1,0,1,0,1,0,0,0,0")) (rule "castedGetAny" (formula "24") (term "0,0,0,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,1,1,0,0,1,0,1,0,0,0")) (rule "castedGetAny" (formula "24") (term "0,1,0,0,1,0,1,0,0,0")) (rule "eqSymm" (formula "24") (term "1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1")) - (rule "eqSymm" (formula "24") (term "0,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,2,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,1")) - (rule "eqSymm" (formula "24") (term "1,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,2,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "2,1,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,0,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,0,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1")) - (rule "eqSymm" (formula "24") (term "0,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,2,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1")) - (rule "eqSymm" (formula "24") (term "1,1")) - (rule "castedGetAny" (formula "24") (term "2,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,0,0")) - (rule "castedGetAny" (formula "24") (term "0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,0,1,0,1,0,1,0,1,0,0,0")) (rule "castedGetAny" (formula "24") (term "0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "2,1,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,0,0,0,1,0,1,0,0,0")) - (rule "subsetSingletonLeft" (formula "24") (term "0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1,0,0,1,0,1,0,0,0")) - (rule "castedGetAny" (formula "24") (term "1,0,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1")) - (rule "eqSymm" (formula "24") (term "0,1")) - (rule "castedGetAny" (formula "24") (term "2,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,1")) - (rule "eqSymm" (formula "24") (term "1,1")) - (rule "inEqSimp_commuteLeq" (formula "24") (term "0,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,2,0,1,0,0")) - (rule "inEqSimp_commuteLeq" (formula "24") (term "0,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_commuteLeq" (formula "24") (term "0,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "2,1,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,0,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "2,0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,0,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1")) - (rule "eqSymm" (formula "24") (term "0,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,2,0,1,1,0,1,0,0,0")) - (rule "castedGetAny" (formula "24") (term "1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1")) - (rule "eqSymm" (formula "24") (term "1,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,2,0,1,0,0")) - (rule "inEqSimp_ltToLeq" (formula "24") (term "1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,1,0,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_ltToLeq" (formula "24") (term "1,0,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,1,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,0,1,0,1,0,0,0,0")) (rule "castedGetAny" (formula "24") (term "1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1,0,1,0,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "24") (term "2,0,1,1,0,1,0,0,0")) + (rule "eqSymm" (formula "24") (term "1,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "24") (term "2,0,1,0,0")) (rule "castedGetAny" (formula "24") (term "2,0,1,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,0,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,0,1")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,0,1,1")) - (rule "eqSymm" (formula "24") (term "1,1")) + (rule "castedGetAny" (formula "24") (term "1,0,1,0,0,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "24") (term "1,0,1,1,0,1,0,0,0")) + (rule "eqSymm" (formula "24") (term "1,1,0,1,0,0,0")) (rule "inEqSimp_ltToLeq" (formula "24") (term "1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "24") (term "0,1,1")) - (rule "eqSymm" (formula "24") (term "1,1")) - (rule "inEqSimp_sepPosMonomial0" (formula "24") (term "1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_rightDist" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_mulLiterals" (formula "24") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "mul_literals" (formula "24") (term "0,1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_elimOne" (formula "24") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_sepPosMonomial0" (formula "24") (term "1,0,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "24") (term "1,1,0,0,1,0,0,0")) - (rule "polySimp_rightDist" (formula "24") (term "1,1,0,0,1,0,0,0")) - (rule "polySimp_mulLiterals" (formula "24") (term "1,1,1,0,0,1,0,0,0")) - (rule "mul_literals" (formula "24") (term "0,1,1,0,0,1,0,0,0")) - (rule "polySimp_elimOne" (formula "24") (term "1,1,1,0,0,1,0,0,0")) + (rule "inEqSimp_ltToLeq" (formula "24") (term "1,0,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,1,0,0,1,0,0,0")) + (rule "inEqSimp_ltToLeq" (formula "24") (term "1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,1,0,0,1,0,1,0,1,0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "24") (term "0,0,0,1,0,1,0,0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "24") (term "0,0,0,1,0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "24") (term "0,0,0,1,0,1,0,1,0,0,0")) (rule "inEqSimp_sepPosMonomial0" (formula "24") (term "1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_mulComm0" (formula "24") (term "1,1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_rightDist" (formula "24") (term "1,1,0,0,1,0,1,0,0,0,0")) (rule "mul_literals" (formula "24") (term "0,1,1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_mulLiterals" (formula "24") (term "1,1,1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_elimOne" (formula "24") (term "1,1,1,0,0,1,0,1,0,0,0,0")) - (rule "pullOutSelect" (formula "24") (term "0,0,0,1,0") (inst "selectSK=LinkedList_size_0")) + (rule "inEqSimp_sepPosMonomial0" (formula "24") (term "1,0,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,1,0,0,1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,1,0,0,1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,1,0,0,1,0,0,0")) + (rule "polySimp_mulLiterals" (formula "24") (term "1,1,1,0,0,1,0,0,0")) + (rule "polySimp_elimOne" (formula "24") (term "1,1,1,0,0,1,0,0,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "24") (term "1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_mulLiterals" (formula "24") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_elimOne" (formula "24") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "pullOutSelect" (formula "24") (term "1,1,0,0,0,0") (inst "selectSK=List_footprint_0:LocSet")) + (rule "applyEq" (formula "25") (term "2,0,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "2,1,0,0,0,0,0") (ifseqformula "1")) + (rule "simplifySelectOfCreate" (formula "1")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) + (rule "applyEqReverse" (formula "25") (term "2,0,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "2,1,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "1,1,0,0,0,0") (ifseqformula "1")) + (rule "hideAuxiliaryEq" (formula "1")) + (rule "elementOfUnionEQ" (formula "24") (term "0,0,0,0,0,0") (ifseqformula "14")) + (builtin "One Step Simplification" (formula "24")) + (rule "elementOfUnionEQ" (formula "24") (term "0,0,0,0,0") (ifseqformula "14")) + (builtin "One Step Simplification" (formula "24")) + (rule "pullOutSelect" (formula "24") (term "1,1,1,0,0,1,0,0,0,0,0") (inst "selectSK=LinkedList_size_0:int")) (rule "applyEq" (formula "25") (term "1,1,1,0,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "0,0,0,1,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "1,1,1,0,0,1,0,1,0,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "0,0,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "1,1,2,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "1,0,1") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "1,1,0,0,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "1,0,1") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "1,1,1") (ifseqformula "1")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) - (rule "applyEqReverse" (formula "25") (term "0,0,0,1,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "1,1,1,0,0,1,0,0,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "1,1,1,0,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "1,1,0,0,1,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "0,0,0,1,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "1,1,1,0,0,1,0,1,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,0,0,1,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "1,1,2,0,1,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "1,0,1") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "1,1,0,0,1,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "1,1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "pullOutSelect" (formula "24") (term "1,1,0") (inst "selectSK=LinkedList_last_0")) - (rule "simplifySelectOfCreate" (formula "1")) - (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) - (rule "applyEqReverse" (formula "25") (term "1,1,0") (ifseqformula "1")) - (rule "hideAuxiliaryEq" (formula "1")) - (rule "pullOutSelect" (formula "24") (term "1,1,0,0") (inst "selectSK=LinkedList_first_0")) - (rule "simplifySelectOfCreate" (formula "1")) - (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) - (rule "applyEqReverse" (formula "25") (term "1,1,0,0") (ifseqformula "1")) - (rule "hideAuxiliaryEq" (formula "1")) - (rule "pullOutSelect" (formula "24") (term "1,1,0,0,0,0") (inst "selectSK=List_footprint_0")) - (rule "applyEq" (formula "25") (term "2,0,0,0,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "2,1,0,0,0,0,0") (ifseqformula "1")) - (rule "simplifySelectOfCreate" (formula "1")) - (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) - (rule "applyEqReverse" (formula "25") (term "1,1,0,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "2,0,0,0,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "2,1,0,0,0,0,0") (ifseqformula "1")) - (rule "hideAuxiliaryEq" (formula "1")) - (rule "elementOfUnionEQ" (formula "24") (term "0,0,0,0,0,0") (ifseqformula "14")) - (builtin "One Step Simplification" (formula "24")) - (rule "elementOfUnionEQ" (formula "24") (term "0,0,0,0,0") (ifseqformula "14")) - (builtin "One Step Simplification" (formula "24")) - (rule "pullOutSelect" (formula "24") (term "0,0,1,0,1,0,0,0,0,0") (inst "selectSK=LinkedList_nodeseq_0")) - (rule "applyEq" (formula "25") (term "0,1,1,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "0,2,0,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "0,2,0,1,0,0") (ifseqformula "1")) + (rule "pullOutSelect" (formula "24") (term "0,0,1,0,1,0,0,0,0,0") (inst "selectSK=LinkedList_nodeseq_0:Seq")) + (rule "applyEq" (formula "25") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "0,1,0,1,0,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "0,1,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "0,2,0,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "0,1,1,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "25") (term "0,2,0,1,0,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "0,2,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "25") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "0,0,1,1") (ifseqformula "1")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) (rule "applyEqReverse" (formula "25") (term "0,0,1,0,1,0,0,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "0,1,1,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "0,2,0,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "0,2,0,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "0,1,0,1,0,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "0,1,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,2,0,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,1,1,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,2,0,1,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "0,2,0,1,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "25") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "0,0,1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "replace_known_left" (formula "24") (term "1,1") (ifseqformula "19")) - (builtin "One Step Simplification" (formula "24") (ifInst "" (formula "14")) (ifInst "" (formula "16")) (ifInst "" (formula "17"))) - (rule "pullOutSelect" (formula "24") (term "0,1,1,0,0,1,0,0") (inst "selectSK=List_seq_0")) + (rule "replace_known_left" (formula "24") (term "0,0,0,0") (ifseqformula "14")) + (builtin "One Step Simplification" (formula "24") (ifInst "" (formula "19"))) + (rule "applyEq" (formula "24") (term "0,1,0,0") (ifseqformula "16")) + (rule "eqSymm" (formula "24") (term "1,0,0")) + (rule "applyEq" (formula "24") (term "0,1,0") (ifseqformula "17")) + (rule "eqSymm" (formula "24") (term "1,0")) + (rule "pullOutSelect" (formula "24") (term "0,1,1,0,0,1,0,0,0,0") (inst "selectSK=List_seq_0:Seq")) (rule "applyEq" (formula "25") (term "0,0,1") (ifseqformula "1")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) - (rule "applyEqReverse" (formula "25") (term "0,1,1,0,0,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "25") (term "0,1,1,0,0,1,0,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "25") (term "0,0,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) (rule "replace_known_left" (formula "24") (term "1") (ifseqformula "18")) (builtin "One Step Simplification" (formula "24")) - (rule "allRight" (formula "24") (inst "sk=i_0")) - (rule "impRight" (formula "24")) + (rule "pullOutSelect" (formula "24") (term "0,1,0") (inst "selectSK=LinkedList_first_0:Node")) + (rule "simplifySelectOfCreate" (formula "1")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) + (rule "applyEqReverse" (formula "25") (term "0,1,0") (ifseqformula "1")) + (builtin "One Step Simplification" (formula "25")) + (rule "hideAuxiliaryEq" (formula "1")) + (rule "pullOutSelect" (formula "24") (term "0,1") (inst "selectSK=LinkedList_last_0:Node")) + (rule "simplifySelectOfCreate" (formula "1")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "23"))) + (rule "applyEqReverse" (formula "25") (term "0,1") (ifseqformula "1")) + (builtin "One Step Simplification" (formula "25")) + (rule "allRight" (formula "25") (inst "sk=i_0:int")) + (rule "impRight" (formula "25")) (rule "andLeft" (formula "1")) + (rule "hideAuxiliaryEq" (formula "3")) (rule "polySimp_homoEq" (formula "26") (term "0,0,1")) (rule "polySimp_addComm1" (formula "26") (term "0,0,0,1")) (rule "inEqSimp_homoInEq0" (formula "2")) @@ -908,8 +825,8 @@ (rule "polySimp_sepPosMonomial" (formula "26") (term "0,0,1")) (rule "polySimp_mulComm0" (formula "26") (term "1,0,0,1")) (rule "polySimp_rightDist" (formula "26") (term "1,0,0,1")) - (rule "polySimp_mulLiterals" (formula "26") (term "1,1,0,0,1")) (rule "mul_literals" (formula "26") (term "0,1,0,0,1")) + (rule "polySimp_mulLiterals" (formula "26") (term "1,1,0,0,1")) (rule "polySimp_elimOne" (formula "26") (term "1,1,0,0,1")) (rule "inEqSimp_sepPosMonomial1" (formula "2")) (rule "polySimp_mulComm0" (formula "2") (term "1")) @@ -917,32 +834,34 @@ (rule "mul_literals" (formula "2") (term "0,1")) (rule "polySimp_mulLiterals" (formula "2") (term "1,1")) (rule "polySimp_elimOne" (formula "2") (term "1,1")) - (rule "pullOutSelect" (formula "26") (term "1,1") (inst "selectSK=Node_next_0")) + (rule "pullOutSelect" (formula "26") (term "0,1,0,0") (inst "selectSK=Node_data_0:int")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) + (rule "eqSymm" (formula "27") (term "1,0,0")) (rule "eqSymm" (formula "1") (term "0,0")) - (rule "pullOutSelect" (formula "27") (term "0,1,0,0") (inst "selectSK=Node_data_0")) + (rule "pullOutSelect" (formula "27") (term "1,1") (inst "selectSK=Node_next_0:Node")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) - (rule "eqSymm" (formula "28") (term "1,0,0")) (rule "eqSymm" (formula "1") (term "0,0")) - (rule "dismissNonSelectedField" (formula "1") (term "2,0")) - (rule "dismissNonSelectedField" (formula "1") (term "2,0")) - (rule "pullOutSelect" (formula "2") (term "2,0") (inst "selectSK=Node_next_1")) + (rule "pullOutSelect" (formula "2") (term "2,0") (inst "selectSK=Node_data_1:int")) (rule "simplifySelectOfCreate" (formula "2")) (builtin "One Step Simplification" (formula "2") (ifInst "" (formula "27"))) (rule "applyEqReverse" (formula "3") (term "2,0") (ifseqformula "2")) (rule "hideAuxiliaryEq" (formula "2")) - (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=Node_data_1")) + (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=Node_next_1:Node")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "27"))) (rule "applyEqReverse" (formula "2") (term "2,0") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) (rule "nnf_imp2or" (formula "28") (term "0,1,0")) - (rule "shift_paren_or" (formula "9")) (rule "nnf_notAnd" (formula "28") (term "0,0,1,0")) + (rule "inEqSimp_notGeq" (formula "28") (term "0,0,0,1,0")) + (rule "mul_literals" (formula "28") (term "1,0,0,0,0,0,1,0")) + (rule "add_literals" (formula "28") (term "0,0,0,0,0,1,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "28") (term "0,0,0,1,0")) + (rule "mul_literals" (formula "28") (term "1,0,0,0,1,0")) (rule "inEqSimp_notLeq" (formula "28") (term "1,0,0,1,0")) (rule "polySimp_rightDist" (formula "28") (term "1,0,0,1,0,0,1,0")) (rule "mul_literals" (formula "28") (term "0,1,0,0,1,0,0,1,0")) @@ -952,60 +871,56 @@ (rule "inEqSimp_sepPosMonomial1" (formula "28") (term "1,0,0,1,0")) (rule "polySimp_mulLiterals" (formula "28") (term "1,1,0,0,1,0")) (rule "polySimp_elimOne" (formula "28") (term "1,1,0,0,1,0")) - (rule "inEqSimp_notGeq" (formula "28") (term "0,0,0,1,0")) - (rule "mul_literals" (formula "28") (term "1,0,0,0,0,0,1,0")) - (rule "add_zero_right" (formula "28") (term "0,0,0,0,0,1,0")) - (rule "inEqSimp_sepPosMonomial0" (formula "28") (term "0,0,0,1,0")) - (rule "mul_literals" (formula "28") (term "1,0,0,0,1,0")) (rule "nnf_imp2or" (formula "28") (term "1,0,1,0")) + (rule "shift_paren_or" (formula "9")) (rule "shift_paren_or" (formula "19") (term "0,1,0,1,0")) (rule "ifthenelse_to_or_left" (formula "19") (term "1,1,0")) - (rule "eqSymm" (formula "19") (term "1,1,1,1,0")) (rule "eqSymm" (formula "19") (term "1,0,1,1,0")) + (rule "eqSymm" (formula "19") (term "1,1,1,1,0")) (rule "ifthenelse_split" (formula "20") (term "0")) (branch "self.size = 0 TRUE" (rule "eqSymm" (formula "21")) (rule "replace_known_left" (formula "22") (term "0,0") (ifseqformula "20")) (builtin "One Step Simplification" (formula "22")) (rule "eqSymm" (formula "22")) + (rule "applyEq" (formula "29") (term "1,1,0,0,1,0") (ifseqformula "20")) + (rule "applyEq" (formula "29") (term "0,0,0,1") (ifseqformula "20")) + (rule "polySimp_homoEq" (formula "29") (term "0,0,1")) + (rule "mul_literals" (formula "29") (term "1,0,0,0,1")) + (rule "add_zero_right" (formula "29") (term "0,0,0,1")) (rule "applyEq" (formula "11") (term "0") (ifseqformula "20")) (rule "inEqSimp_homoInEq1" (formula "11")) (rule "mul_literals" (formula "11") (term "1,0")) (rule "add_zero_right" (formula "11") (term "0")) - (rule "applyEq" (formula "5") (term "0") (ifseqformula "20")) - (rule "inEqSimp_homoInEq1" (formula "5")) - (rule "mul_literals" (formula "5") (term "1,0")) - (rule "add_zero_right" (formula "5") (term "0")) (rule "applyEq" (formula "4") (term "0") (ifseqformula "20")) (rule "inEqSimp_homoInEq1" (formula "4")) (rule "mul_literals" (formula "4") (term "1,0")) (rule "add_zero_right" (formula "4") (term "0")) - (rule "applyEq" (formula "19") (term "1,1,0,0,0,1,0,1,0") (ifseqformula "20")) - (rule "applyEq" (formula "29") (term "1,1,0,0,1,0") (ifseqformula "20")) - (rule "applyEq" (formula "29") (term "0,0,0,1") (ifseqformula "20")) - (rule "polySimp_homoEq" (formula "29") (term "0,0,1")) - (rule "mul_literals" (formula "29") (term "1,0,0,0,1")) - (rule "add_zero_right" (formula "29") (term "0,0,0,1")) + (rule "applyEq" (formula "5") (term "0") (ifseqformula "20")) + (rule "inEqSimp_homoInEq1" (formula "5")) + (rule "mul_literals" (formula "5") (term "1,0")) + (rule "add_zero_right" (formula "5") (term "0")) (rule "applyEq" (formula "19") (term "1,1,0,0") (ifseqformula "20")) (rule "applyEq" (formula "18") (term "1,1,1,0,0,1,0") (ifseqformula "20")) (rule "add_literals" (formula "18") (term "1,1,0,0,1,0")) - (rule "applyEq" (formula "23") (term "1") (ifseqformula "20")) - (rule "applyEq" (formula "24") (term "1") (ifseqformula "20")) + (rule "applyEq" (formula "19") (term "1,1,0,0,0,1,0,1,0") (ifseqformula "20")) (rule "applyEq" (formula "19") (term "1,1,0,0,0,1,1,0") (ifseqformula "20")) (rule "add_literals" (formula "19") (term "1,0,0,0,1,1,0")) (rule "applyEq" (formula "19") (term "1,1,0,1,1,1,0") (ifseqformula "20")) (rule "add_literals" (formula "19") (term "1,0,1,1,1,0")) + (rule "applyEq" (formula "24") (term "1") (ifseqformula "20")) + (rule "applyEq" (formula "23") (term "1") (ifseqformula "20")) (rule "polySimp_sepPosMonomial" (formula "29") (term "0,0,1")) (rule "mul_literals" (formula "29") (term "1,0,0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "11")) (rule "mul_literals" (formula "11") (term "1")) - (rule "inEqSimp_sepPosMonomial0" (formula "5")) - (rule "mul_literals" (formula "5") (term "1")) (rule "inEqSimp_sepPosMonomial0" (formula "4")) (rule "mul_literals" (formula "4") (term "1")) + (rule "inEqSimp_sepPosMonomial0" (formula "5")) + (rule "mul_literals" (formula "5") (term "1")) (rule "inEqSimp_contradEq7" (formula "29") (term "0,0,1") (ifseqformula "3")) - (rule "mul_literals" (formula "29") (term "1,0,0,0,0,1")) (rule "add_zero_left" (formula "29") (term "0,0,0,0,1")) + (rule "mul_literals" (formula "29") (term "0,0,0,0,1")) (rule "leq_literals" (formula "29") (term "0,0,0,1")) (builtin "One Step Simplification" (formula "29")) (rule "inEqSimp_contradInEq0" (formula "3") (ifseqformula "4")) @@ -1016,45 +931,44 @@ (branch "self.size = 0 FALSE" (rule "replace_known_right" (formula "21") (term "0,0") (ifseqformula "24")) (builtin "One Step Simplification" (formula "21")) - (rule "lenNonNegative" (formula "22") (term "0")) - (rule "inEqSimp_commuteLeq" (formula "22")) - (rule "applyEq" (formula "22") (term "0") (ifseqformula "23")) - (rule "inEqSimp_strengthen1" (formula "22") (ifseqformula "25")) - (rule "add_literals" (formula "22") (term "1")) - (rule "inEqSimp_contradEq7" (formula "25") (ifseqformula "22")) + (rule "commute_or" (formula "19") (term "0,1,1,0")) + (rule "commute_or" (formula "19") (term "1,1,1,0")) + (rule "commute_or_2" (formula "19") (term "0,0,1,0,1,0")) + (rule "commute_or" (formula "19") (term "0,0,0,1,0,1,0")) + (rule "seqGetAlphaCast" (formula "25") (term "1,0")) + (rule "castedGetAny" (formula "1") (term "0")) + (builtin "One Step Simplification" (formula "1")) + (rule "true_left" (formula "1")) + (rule "seqGetAlphaCast" (formula "12") (term "0")) + (rule "castedGetAny" (formula "12") (term "0")) + (builtin "One Step Simplification" (formula "12")) + (rule "true_left" (formula "12")) + (rule "lenNonNegative" (formula "23") (term "0")) + (rule "inEqSimp_commuteLeq" (formula "23")) + (rule "applyEq" (formula "23") (term "0") (ifseqformula "24")) + (rule "inEqSimp_strengthen1" (formula "23") (ifseqformula "25")) + (rule "add_literals" (formula "23") (term "1")) + (rule "inEqSimp_contradEq7" (formula "25") (ifseqformula "23")) (rule "mul_literals" (formula "25") (term "1,0,0")) (rule "add_literals" (formula "25") (term "0,0")) (rule "leq_literals" (formula "25") (term "0")) (builtin "One Step Simplification" (formula "25")) (rule "false_right" (formula "25")) - (rule "lenNonNegative" (formula "24") (term "0")) - (rule "inEqSimp_commuteLeq" (formula "24")) - (rule "applyEq" (formula "24") (term "0") (ifseqformula "25")) - (rule "inEqSimp_subsumption1" (formula "24") (ifseqformula "22")) - (rule "leq_literals" (formula "24") (term "0")) - (builtin "One Step Simplification" (formula "24")) - (rule "true_left" (formula "24")) - (rule "seqGetAlphaCast" (formula "12") (term "0")) - (rule "castedGetAny" (formula "12") (term "0")) - (builtin "One Step Simplification" (formula "12")) - (rule "true_left" (formula "12")) - (rule "seqGetAlphaCast" (formula "25") (term "1,0")) - (rule "castedGetAny" (formula "1") (term "0")) - (builtin "One Step Simplification" (formula "1")) - (rule "true_left" (formula "1")) + (rule "lenNonNegative" (formula "22") (term "0")) + (rule "inEqSimp_commuteLeq" (formula "22")) + (rule "applyEq" (formula "22") (term "0") (ifseqformula "23")) + (rule "inEqSimp_subsumption1" (formula "22") (ifseqformula "24")) + (rule "leq_literals" (formula "22") (term "0")) + (builtin "One Step Simplification" (formula "22")) + (rule "true_left" (formula "22")) (rule "seqGetAlphaCast" (formula "7") (term "1,0")) (rule "castedGetAny" (formula "7") (term "0")) (builtin "One Step Simplification" (formula "7")) (rule "true_left" (formula "7")) - (rule "commute_or" (formula "19") (term "1,1,1,0")) - (rule "commute_or" (formula "19") (term "0,1,1,0")) - (rule "commute_or_2" (formula "19") (term "0,0,1,0,1,0")) - (rule "commute_or" (formula "19") (term "0,0,0,1,0,1,0")) (rule "ifthenelse_split" (formula "29") (term "0,1")) (branch "self.size = 1 + i_0 TRUE" (rule "eqSymm" (formula "30") (term "1")) (rule "applyEq" (formula "30") (term "1,1,0,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "20") (term "1,1,0,0,1,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "12") (term "0") (ifseqformula "1")) (rule "inEqSimp_homoInEq1" (formula "12")) (rule "polySimp_mulComm0" (formula "12") (term "1,0")) @@ -1064,6 +978,21 @@ (rule "polySimp_addAssoc" (formula "12") (term "0,0")) (rule "add_literals" (formula "12") (term "0,0,0")) (rule "add_zero_left" (formula "12") (term "0,0")) + (rule "applyEq" (formula "5") (term "0") (ifseqformula "1")) + (rule "inEqSimp_homoInEq1" (formula "5")) + (rule "polySimp_pullOutFactor1" (formula "5") (term "0")) + (rule "add_literals" (formula "5") (term "1,0")) + (rule "times_zero_1" (formula "5") (term "0")) + (rule "leq_literals" (formula "5")) + (rule "true_left" (formula "5")) + (rule "applyEq" (formula "5") (term "0") (ifseqformula "1")) + (rule "inEqSimp_homoInEq1" (formula "5")) + (rule "polySimp_mulComm0" (formula "5") (term "1,0")) + (rule "polySimp_rightDist" (formula "5") (term "1,0")) + (rule "mul_literals" (formula "5") (term "0,1,0")) + (rule "polySimp_addComm1" (formula "5") (term "0")) + (rule "polySimp_addAssoc" (formula "5") (term "0,0")) + (rule "add_literals" (formula "5") (term "0,0,0")) (rule "applyEq" (formula "23") (term "0") (ifseqformula "1")) (rule "inEqSimp_homoInEq1" (formula "23")) (rule "polySimp_mulComm0" (formula "23") (term "1,0")) @@ -1072,61 +1001,50 @@ (rule "polySimp_addAssoc" (formula "23") (term "0")) (rule "add_literals" (formula "23") (term "0,0")) (rule "add_zero_left" (formula "23") (term "0")) - (rule "applyEq" (formula "22") (term "1,1,0") (ifseqformula "1")) - (rule "polySimp_addAssoc" (formula "22") (term "1,0")) - (rule "add_literals" (formula "22") (term "0,1,0")) - (rule "add_zero_left" (formula "22") (term "1,0")) - (rule "applyEq" (formula "6") (term "0") (ifseqformula "1")) - (rule "inEqSimp_homoInEq1" (formula "6")) - (rule "polySimp_mulComm0" (formula "6") (term "1,0")) - (rule "polySimp_rightDist" (formula "6") (term "1,0")) - (rule "mul_literals" (formula "6") (term "0,1,0")) - (rule "polySimp_addComm1" (formula "6") (term "0")) - (rule "polySimp_addAssoc" (formula "6") (term "0,0")) - (rule "add_literals" (formula "6") (term "0,0,0")) - (rule "applyEq" (formula "5") (term "0") (ifseqformula "1")) - (rule "inEqSimp_homoInEq1" (formula "5")) - (rule "polySimp_pullOutFactor1" (formula "5") (term "0")) - (rule "add_literals" (formula "5") (term "1,0")) - (rule "times_zero_1" (formula "5") (term "0")) - (rule "leq_literals" (formula "5")) - (rule "true_left" (formula "5")) (rule "applyEq" (formula "19") (term "1,1,0,0") (ifseqformula "1")) (rule "applyEq" (formula "18") (term "1,1,1,0,0,1,0") (ifseqformula "1")) (rule "polySimp_addAssoc" (formula "18") (term "1,1,0,0,1,0")) (rule "add_literals" (formula "18") (term "0,1,1,0,0,1,0")) (rule "add_zero_left" (formula "18") (term "1,1,0,0,1,0")) - (rule "applyEq" (formula "29") (term "0,0,0,0,0") (ifseqformula "21")) - (rule "applyEq" (formula "3") (term "1,2,0") (ifseqformula "21")) - (rule "applyEq" (formula "29") (term "1,0,0,1,0,1,0") (ifseqformula "21")) - (rule "applyEq" (formula "2") (term "1,2,0") (ifseqformula "21")) - (rule "applyEq" (formula "2") (term "0,0,0") (ifseqformula "21")) - (rule "applyEq" (formula "3") (term "0,0,0") (ifseqformula "21")) - (rule "applyEq" (formula "23") (term "1") (ifseqformula "1")) + (rule "applyEq" (formula "19") (term "1,1,0,0,1,0,1,0") (ifseqformula "1")) + (rule "applyEq" (formula "21") (term "1,1,0") (ifseqformula "1")) + (rule "polySimp_addAssoc" (formula "21") (term "1,0")) + (rule "add_literals" (formula "21") (term "0,1,0")) + (rule "add_zero_left" (formula "21") (term "1,0")) (rule "applyEq" (formula "19") (term "1,1,0,1,0,1,1,0") (ifseqformula "1")) (rule "polySimp_addAssoc" (formula "19") (term "1,0,1,0,1,1,0")) (rule "add_literals" (formula "19") (term "0,1,0,1,0,1,1,0")) (rule "add_zero_left" (formula "19") (term "1,0,1,0,1,1,0")) - (rule "applyEq" (formula "24") (term "1") (ifseqformula "1")) (rule "applyEq" (formula "19") (term "1,1,1,1,1,1,0") (ifseqformula "1")) (rule "polySimp_addAssoc" (formula "19") (term "1,1,1,1,1,0")) (rule "add_literals" (formula "19") (term "0,1,1,1,1,1,0")) (rule "add_zero_left" (formula "19") (term "1,1,1,1,1,0")) + (rule "applyEq" (formula "24") (term "1") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "1") (ifseqformula "1")) + (rule "applyEq" (formula "29") (term "0,0,0,0,0") (ifseqformula "21")) + (rule "applyEq" (formula "29") (term "1,0,0,1,0,1,0") (ifseqformula "21")) + (rule "applyEq" (formula "2") (term "0,0,0") (ifseqformula "21")) + (rule "applyEq" (formula "3") (term "0,0,0") (ifseqformula "21")) + (rule "applyEq" (formula "2") (term "1,2,0") (ifseqformula "21")) + (rule "applyEq" (formula "3") (term "1,2,0") (ifseqformula "21")) (rule "inEqSimp_sepPosMonomial0" (formula "11")) (rule "polySimp_mulLiterals" (formula "11") (term "1")) (rule "polySimp_elimOne" (formula "11") (term "1")) - (rule "inEqSimp_invertInEq0" (formula "22")) - (rule "mul_literals" (formula "22") (term "1")) - (rule "polySimp_mulLiterals" (formula "22") (term "0")) - (rule "polySimp_elimOne" (formula "22") (term "0")) (rule "inEqSimp_sepPosMonomial0" (formula "5")) (rule "polySimp_mulComm0" (formula "5") (term "1")) (rule "polySimp_rightDist" (formula "5") (term "1")) (rule "mul_literals" (formula "5") (term "0,1")) (rule "polySimp_mulLiterals" (formula "5") (term "1,1")) (rule "polySimp_elimOne" (formula "5") (term "1,1")) + (rule "inEqSimp_invertInEq0" (formula "23")) + (rule "polySimp_mulLiterals" (formula "23") (term "0")) + (rule "mul_literals" (formula "23") (term "1")) + (rule "polySimp_elimOne" (formula "23") (term "0")) + (rule "inEqSimp_exactShadow3" (formula "10") (ifseqformula "11")) + (rule "mul_literals" (formula "10") (term "0,0")) + (rule "add_zero_left" (formula "10") (term "0")) (rule "inEqSimp_exactShadow3" (formula "6") (ifseqformula "5")) - (rule "times_zero_1" (formula "6") (term "0,0")) + (rule "mul_literals" (formula "6") (term "0,0")) (rule "add_zero_left" (formula "6") (term "0")) (rule "inEqSimp_sepPosMonomial1" (formula "6")) (rule "mul_literals" (formula "6") (term "1")) @@ -1134,41 +1052,34 @@ (rule "leq_literals" (formula "4") (term "0")) (builtin "One Step Simplification" (formula "4")) (rule "true_left" (formula "4")) - (rule "inEqSimp_exactShadow3" (formula "10") (ifseqformula "11")) - (rule "mul_literals" (formula "10") (term "0,0")) - (rule "add_zero_left" (formula "10") (term "0")) - (rule "inEqSimp_subsumption1" (formula "10") (ifseqformula "5")) - (rule "leq_literals" (formula "10") (term "0")) - (builtin "One Step Simplification" (formula "10")) - (rule "true_left" (formula "10")) (rule "all_pull_out1" (formula "19") (term "0,1,0")) (rule "seqGetAlphaCast" (formula "28") (term "0,1,0,0")) (rule "castedGetAny" (formula "1") (term "0")) (builtin "One Step Simplification" (formula "1")) (rule "true_left" (formula "1")) - (rule "cut_direct" (formula "9") (term "1,0")) - (branch "CUT: fv_0 = Node::#next TRUE" + (rule "cut_direct" (formula "9") (term "0,0")) + (branch "CUT: fv_0 = Node::#data TRUE" (builtin "One Step Simplification" (formula "10")) (rule "true_left" (formula "10")) (rule "seqGetAlphaCast" (formula "20") (term "0")) (rule "castedGetAny" (formula "20") (term "0")) (builtin "One Step Simplification" (formula "20")) (rule "true_left" (formula "20")) - (rule "ifthenelse_split" (formula "3") (term "0")) + (rule "all_pull_out0" (formula "19") (term "1,0")) + (rule "shift_paren_and" (formula "19") (term "0,1,0")) + (rule "onlyCreatedObjectsAreReferenced" (formula "20") (term "1") (ifseqformula "14")) + (rule "ifthenelse_split" (formula "2") (term "0")) (branch "self.last = n_2 TRUE" - (rule "referencedObjectIsCreatedRightEQ" (formula "26") (ifseqformula "3") (ifseqformula "27")) - (rule "close" (formula "26") (ifseqformula "15")) + (rule "referencedObjectIsCreatedRightEQ" (formula "27") (ifseqformula "2") (ifseqformula "28")) + (rule "close" (formula "27") (ifseqformula "15")) ) (branch "self.last = n_2 FALSE" - (rule "applyEqReverse" (formula "29") (term "0,1") (ifseqformula "3")) - (rule "hideAuxiliaryEq" (formula "3")) - (rule "replace_known_right" (formula "2") (term "0,0") (ifseqformula "23")) + (rule "applyEqReverse" (formula "30") (term "0,1") (ifseqformula "2")) + (rule "hideAuxiliaryEq" (formula "2")) + (rule "replace_known_right" (formula "2") (term "0,0") (ifseqformula "24")) (builtin "One Step Simplification" (formula "2")) - (rule "applyEqReverse" (formula "28") (term "1,1,0,0") (ifseqformula "2")) + (rule "applyEqReverse" (formula "29") (term "1,1,0,0") (ifseqformula "2")) (rule "hideAuxiliaryEq" (formula "2")) - (rule "all_pull_out0" (formula "17") (term "1,0")) - (rule "shift_paren_and" (formula "17") (term "0,1,0")) - (rule "onlyCreatedObjectsAreReferenced" (formula "18") (term "1") (ifseqformula "12")) (rule "all_pull_out3" (formula "17") (term "0")) (rule "cnf_rightDist" (formula "17") (term "0,0")) (rule "distr_forallAnd" (formula "17") (term "0")) @@ -1218,151 +1129,332 @@ (rule "castedGetAny" (formula "24") (term "0")) (builtin "One Step Simplification" (formula "24")) (rule "true_left" (formula "24")) - (rule "allLeft" (formula "21") (inst "t=nv_0")) - (rule "inEqSimp_contradInEq0" (formula "21") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "21") (term "0,1")) - (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "21") (term "1,0,0,1")) - (rule "mul_literals" (formula "21") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "21") (term "0,0,1")) - (rule "polySimp_addComm0" (formula "21") (term "0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "21") (term "0,0,1")) - (rule "add_literals" (formula "21") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "21") (term "1,0,0,1")) - (rule "add_literals" (formula "21") (term "0,0,1")) - (rule "leq_literals" (formula "21") (term "0,1")) - (builtin "One Step Simplification" (formula "21")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "21") (term "0,1")) - (builtin "One Step Simplification" (formula "21")) - (rule "allLeft" (formula "22") (inst "t=Z(0(#))")) - (rule "leq_literals" (formula "22") (term "1,0")) - (builtin "One Step Simplification" (formula "22")) - (rule "add_literals" (formula "22") (term "1,1,0")) - (rule "inEqSimp_commuteGeq" (formula "22") (term "1")) - (rule "applyEq" (formula "22") (term "1,0,0") (ifseqformula "25")) - (rule "eqSymm" (formula "22") (term "0")) - (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "3")) - (rule "qeq_literals" (formula "22") (term "0,1")) - (builtin "One Step Simplification" (formula "22")) - (rule "allLeft" (formula "19") (inst "t=nv_0")) - (rule "inEqSimp_contradInEq1" (formula "19") (term "1,0,0,0,0,0") (ifseqformula "4")) - (rule "qeq_literals" (formula "19") (term "0,1,0,0,0,0,0")) - (builtin "One Step Simplification" (formula "19")) - (rule "inEqSimp_contradInEq0" (formula "19") (term "1,0,0,0,0") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "19") (term "0,1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "mul_literals" (formula "19") (term "0,1,0,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "polySimp_addComm1" (formula "19") (term "0,0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "0,0,0,0,1,0,0,0,0")) - (rule "polySimp_pullOutFactor1b" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "1,1,0,0,1,0,0,0,0")) - (rule "times_zero_1" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "leq_literals" (formula "19") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "19")) - (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0,0,0,0,0")) - (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0,0,0,0,0")) - (rule "mul_literals" (formula "20") (term "0,1,0,1,0,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "20") (term "0,1,0,0,0,0,0")) - (rule "add_literals" (formula "20") (term "0,0,1,0,0,0,0,0")) - (rule "inEqSimp_homoInEq1" (formula "20") (term "1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0,0,0,0")) - (rule "mul_literals" (formula "20") (term "0,1,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "20") (term "0,1,0,0,0,0")) - (rule "polySimp_addComm1" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "20") (term "0,0,0,1,0,0,0,0")) - (rule "add_zero_left" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0,0,0,0,0")) - (rule "polySimp_elimOne" (formula "20") (term "0,1,0,0,0,0,0")) - (rule "inEqSimp_sepNegMonomial0" (formula "20") (term "1,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0,0,0,0")) - (rule "polySimp_elimOne" (formula "20") (term "0,1,0,0,0,0")) - (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0,0,0,0,0") (ifseqformula "4")) - (rule "qeq_literals" (formula "20") (term "0,1,0,0,0,0,0")) - (builtin "One Step Simplification" (formula "20")) - (rule "inEqSimp_contradInEq0" (formula "20") (term "1,0,0,0,0") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1,0,0,0,0")) - (rule "mul_literals" (formula "20") (term "0,1,0,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "polySimp_addComm0" (formula "20") (term "0,0,0,1,0,0,0,0")) - (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "20") (term "1,1,0,0,1,0,0,0,0")) - (rule "times_zero_1" (formula "20") (term "1,0,0,1,0,0,0,0")) - (rule "add_literals" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "leq_literals" (formula "20") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "20")) - (rule "allLeft" (formula "17") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1,0")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,0")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,0")) - (rule "add_literals" (formula "17") (term "0,0,1,0")) + (rule "allLeft" (formula "18") (inst "t=i_0:int")) + (rule "eqSymm" (formula "18") (term "1")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "1,0")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,1,0")) + (rule "add_literals" (formula "18") (term "1,1,0,1,0")) + (rule "times_zero_1" (formula "18") (term "1,0,1,0")) + (rule "add_literals" (formula "18") (term "0,1,0")) + (rule "leq_literals" (formula "18") (term "1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "applyEq" (formula "18") (term "1,1,1") (ifseqformula "25")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "3")) + (rule "qeq_literals" (formula "18") (term "0,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "replace_known_left" (formula "33") (term "1,0") (ifseqformula "18")) + (builtin "One Step Simplification" (formula "33")) + (rule "allLeft" (formula "17") (inst "t=i_0:int")) (rule "inEqSimp_homoInEq1" (formula "17") (term "1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1")) - (rule "polySimp_addComm1" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,0,1")) - (rule "add_zero_left" (formula "17") (term "0,0,1")) - (rule "inEqSimp_sepNegMonomial1" (formula "17") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "17") (term "0,1,0")) - (rule "inEqSimp_sepNegMonomial0" (formula "17") (term "1")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1")) - (rule "polySimp_elimOne" (formula "17") (term "0,1")) - (rule "inEqSimp_contradInEq0" (formula "17") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "0,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,0,1")) - (rule "polySimp_addComm0" (formula "17") (term "0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "17") (term "1,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "leq_literals" (formula "17") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,1")) + (rule "add_literals" (formula "17") (term "1,1,0,1")) + (rule "times_zero_1" (formula "17") (term "1,0,1")) + (rule "add_literals" (formula "17") (term "0,1")) + (rule "leq_literals" (formula "17") (term "1")) (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "4")) + (rule "applyEq" (formula "17") (term "0,0,0") (ifseqformula "26")) + (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "3")) (rule "qeq_literals" (formula "17") (term "0,1")) (builtin "One Step Simplification" (formula "17")) (rule "notLeft" (formula "17")) - (rule "referencedObjectIsCreatedRightEQ" (formula "33") (ifseqformula "23") (ifseqformula "31")) - (rule "close" (formula "33") (ifseqformula "12")) + (rule "replace_known_right" (formula "34") (term "0,0") (ifseqformula "28")) + (builtin "One Step Simplification" (formula "34")) + (rule "allRight" (formula "34") (inst "sk=j_0:int")) + (rule "orRight" (formula "34")) + (rule "orRight" (formula "34")) + (rule "orRight" (formula "36")) + (rule "notRight" (formula "36")) + (rule "inEqSimp_leqRight" (formula "35")) + (rule "mul_literals" (formula "1") (term "1,0,0")) + (rule "add_literals" (formula "1") (term "0,0")) + (rule "add_zero_left" (formula "1") (term "0")) + (rule "inEqSimp_geqRight" (formula "36")) + (rule "polySimp_rightDist" (formula "1") (term "1,0,0")) + (rule "mul_literals" (formula "1") (term "0,1,0,0")) + (rule "polySimp_addAssoc" (formula "1") (term "0,0")) + (rule "add_literals" (formula "1") (term "0,0,0")) + (rule "add_zero_left" (formula "1") (term "0,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "1")) + (rule "polySimp_mulLiterals" (formula "1") (term "1")) + (rule "polySimp_elimOne" (formula "1") (term "1")) + (rule "inEqSimp_strengthen0" (formula "1") (ifseqformula "37")) + (rule "inEqSimp_contradEq3" (formula "37") (ifseqformula "1")) + (rule "polySimp_mulComm0" (formula "37") (term "1,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "37") (term "0,0")) + (rule "add_literals" (formula "37") (term "1,1,0,0")) + (rule "times_zero_1" (formula "37") (term "1,0,0")) + (rule "add_literals" (formula "37") (term "0,0")) + (rule "qeq_literals" (formula "37") (term "0")) + (builtin "One Step Simplification" (formula "37")) + (rule "false_right" (formula "37")) + (rule "inEqSimp_exactShadow3" (formula "2") (ifseqformula "1")) + (rule "mul_literals" (formula "2") (term "0,0")) + (rule "add_zero_left" (formula "2") (term "0")) + (rule "inEqSimp_sepPosMonomial1" (formula "2")) + (rule "mul_literals" (formula "2") (term "1")) + (rule "allLeft" (formula "25") (inst "t=nv_0:int")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "25") (term "0,1,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq0" (formula "25") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,1")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,1")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,1")) + (rule "polySimp_addComm0" (formula "25") (term "0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,1")) + (rule "add_literals" (formula "25") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "25") (term "1,0,0,1")) + (rule "add_literals" (formula "25") (term "0,0,1")) + (rule "leq_literals" (formula "25") (term "0,1")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "26") (inst "t=Z(0(#)):int")) + (rule "add_literals" (formula "26") (term "1,1,0,0")) + (rule "leq_literals" (formula "26") (term "1,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "inEqSimp_commuteGeq" (formula "26") (term "1")) + (rule "applyEq" (formula "26") (term "1,0,0") (ifseqformula "29")) + (rule "eqSymm" (formula "26") (term "0")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "1") (ifseqformula "6")) + (rule "qeq_literals" (formula "26") (term "0,1")) + (builtin "One Step Simplification" (formula "26")) + (rule "allLeft" (formula "23") (inst "t=nv_0:int")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "23") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq0" (formula "23") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "23") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "23") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "23") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "22") (inst "t=nv_0:int")) + (rule "eqSymm" (formula "22") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "22") (term "0,0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "inEqSimp_contradInEq0" (formula "22") (term "0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "22") (term "0,0")) + (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "22") (term "1,0,0,0")) + (rule "mul_literals" (formula "22") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "22") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "22") (term "0,0,0,0")) + (rule "add_literals" (formula "22") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "22") (term "0,0,0")) + (rule "add_literals" (formula "22") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "22") (term "1,0,0,0")) + (rule "add_literals" (formula "22") (term "0,0,0")) + (rule "leq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "allLeft" (formula "20") (inst "t=nv_0:int")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq0" (formula "20") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "23") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "eqSymm" (formula "23") (term "1")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0")) + (rule "mul_literals" (formula "23") (term "1,0,0")) + (rule "add_zero_right" (formula "23") (term "0,0")) + (rule "applyEq" (formula "23") (term "1,1,1") (ifseqformula "32")) + (rule "inEqSimp_sepPosMonomial0" (formula "23") (term "0")) + (rule "mul_literals" (formula "23") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0") (ifseqformula "6")) + (rule "qeq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "20") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "20") (term "1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "1")) + (rule "mul_literals" (formula "20") (term "1,0,1")) + (rule "add_zero_right" (formula "20") (term "0,1")) + (rule "applyEq" (formula "20") (term "0,0,0") (ifseqformula "33")) + (rule "inEqSimp_sepPosMonomial0" (formula "20") (term "1")) + (rule "mul_literals" (formula "20") (term "1,1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "6")) + (rule "qeq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "replace_known_right" (formula "31") (term "0") (ifseqformula "36")) + (builtin "One Step Simplification" (formula "31")) + (rule "allLeft" (formula "24") (inst "t=i_0_0:int")) + (rule "eqSymm" (formula "24") (term "1")) + (rule "applyEq" (formula "24") (term "1,1,1") (ifseqformula "13")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0,0") (ifseqformula "11")) + (rule "qeq_literals" (formula "24") (term "0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "inEqSimp_contradInEq0" (formula "24") (term "0") (ifseqformula "12")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "24") (term "1,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0")) + (rule "leq_literals" (formula "24") (term "0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "allLeft" (formula "27") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_homoInEq0" (formula "27") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,1,0,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0,1,0,0,0,0")) + (rule "add_zero_left" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "27") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "27") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "27") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "27") (term "1,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_elimOne" (formula "27") (term "0,1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "27") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "inEqSimp_contradInEq0" (formula "27") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm0" (formula "27") (term "0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "27") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "allLeft" (formula "25") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "eqSymm" (formula "25") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "1,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,1,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,1,0")) + (rule "polySimp_addComm1" (formula "25") (term "0,0,1,0")) + (rule "add_literals" (formula "25") (term "0,0,0,1,0")) + (rule "add_zero_left" (formula "25") (term "0,0,1,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "25") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "25") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "25") (term "0,0,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "25") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "25") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "25") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "25") (term "0,0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq0" (formula "25") (term "0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "polySimp_addComm0" (formula "25") (term "0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "25") (term "1,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0")) + (rule "leq_literals" (formula "25") (term "0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,1")) + (rule "add_zero_left" (formula "20") (term "0,0,1")) + (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "20") (term "0,1,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "20") (term "1")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1")) + (rule "polySimp_elimOne" (formula "20") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq0" (formula "20") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm0" (formula "20") (term "0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "referencedObjectIsCreatedRightEQ" (formula "44") (ifseqformula "31") (ifseqformula "39")) + (rule "close" (formula "44") (ifseqformula "15")) ) ) - (branch "CUT: fv_0 = Node::#next FALSE" + (branch "CUT: fv_0 = Node::#data FALSE" (builtin "One Step Simplification" (formula "9")) (rule "seqGetAlphaCast" (formula "20") (term "0")) (rule "castedGetAny" (formula "20") (term "0")) (builtin "One Step Simplification" (formula "20")) (rule "true_left" (formula "20")) - (rule "ifthenelse_split" (formula "3") (term "0")) + (rule "all_pull_out0" (formula "19") (term "1,0")) + (rule "shift_paren_and" (formula "19") (term "0,1,0")) + (rule "onlyCreatedObjectsAreReferenced" (formula "20") (term "1") (ifseqformula "14")) + (rule "ifthenelse_split" (formula "2") (term "0")) (branch "self.last = n_2 TRUE" - (rule "referencedObjectIsCreatedRightEQ" (formula "27") (ifseqformula "3") (ifseqformula "28")) - (rule "close" (formula "27") (ifseqformula "15")) + (rule "referencedObjectIsCreatedRightEQ" (formula "28") (ifseqformula "2") (ifseqformula "29")) + (rule "close" (formula "28") (ifseqformula "15")) ) (branch "self.last = n_2 FALSE" - (rule "applyEqReverse" (formula "30") (term "0,1") (ifseqformula "3")) - (rule "hideAuxiliaryEq" (formula "3")) - (rule "replace_known_right" (formula "2") (term "0,0") (ifseqformula "23")) + (rule "applyEqReverse" (formula "31") (term "0,1") (ifseqformula "2")) + (rule "hideAuxiliaryEq" (formula "2")) + (rule "replace_known_right" (formula "2") (term "0,0") (ifseqformula "24")) (builtin "One Step Simplification" (formula "2")) - (rule "applyEqReverse" (formula "29") (term "1,1,0,0") (ifseqformula "2")) + (rule "applyEqReverse" (formula "30") (term "1,1,0,0") (ifseqformula "2")) (rule "hideAuxiliaryEq" (formula "2")) - (rule "all_pull_out0" (formula "17") (term "1,0")) - (rule "shift_paren_and" (formula "17") (term "0,1,0")) - (rule "onlyCreatedObjectsAreReferenced" (formula "18") (term "1") (ifseqformula "12")) (rule "all_pull_out3" (formula "17") (term "0")) (rule "cnf_rightDist" (formula "17") (term "0,0")) (rule "distr_forallAnd" (formula "17") (term "0")) @@ -1403,8 +1495,8 @@ (rule "cnf_rightDist" (formula "17") (term "0")) (rule "distr_forallAnd" (formula "17")) (rule "andLeft" (formula "17")) - (rule "commute_or_2" (formula "17") (term "0")) (rule "commute_or" (formula "18") (term "0")) + (rule "commute_or_2" (formula "17") (term "0")) (rule "commute_or" (formula "17") (term "0,0")) (rule "commute_or_2" (formula "19") (term "0,0,0,0")) (rule "shift_paren_or" (formula "19") (term "0,0,0,0,0")) @@ -1412,110 +1504,309 @@ (rule "castedGetAny" (formula "24") (term "0")) (builtin "One Step Simplification" (formula "24")) (rule "true_left" (formula "24")) - (rule "allLeft" (formula "21") (inst "t=Z(0(#))")) - (rule "leq_literals" (formula "21") (term "1,0")) - (builtin "One Step Simplification" (formula "21")) - (rule "add_literals" (formula "21") (term "1,1,0")) - (rule "inEqSimp_commuteGeq" (formula "21") (term "1")) - (rule "applyEq" (formula "21") (term "1,0,0") (ifseqformula "24")) - (rule "eqSymm" (formula "21") (term "0")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1") (ifseqformula "3")) - (rule "qeq_literals" (formula "21") (term "0,1")) - (builtin "One Step Simplification" (formula "21")) - (rule "allLeft" (formula "22") (inst "t=nv_0")) - (rule "inEqSimp_contradInEq0" (formula "22") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "22") (term "0,1")) - (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "22") (term "1,0,0,1")) - (rule "mul_literals" (formula "22") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "22") (term "0,0,1")) - (rule "polySimp_addComm0" (formula "22") (term "0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "22") (term "0,0,1")) - (rule "add_literals" (formula "22") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "22") (term "1,0,0,1")) - (rule "add_literals" (formula "22") (term "0,0,1")) - (rule "leq_literals" (formula "22") (term "0,1")) - (builtin "One Step Simplification" (formula "22")) - (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "22") (term "0,1")) - (builtin "One Step Simplification" (formula "22")) - (rule "allLeft" (formula "19") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_homoInEq1" (formula "19") (term "1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "19") (term "1,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "19") (term "1,0,1,0,0,0,0")) - (rule "mul_literals" (formula "19") (term "0,1,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "19") (term "0,1,0,0,0,0")) - (rule "polySimp_addComm1" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "0,0,0,1,0,0,0,0")) - (rule "add_zero_left" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "inEqSimp_homoInEq0" (formula "19") (term "1,0,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "19") (term "1,0,1,0,0,0,0,0")) - (rule "polySimp_rightDist" (formula "19") (term "1,0,1,0,0,0,0,0")) - (rule "mul_literals" (formula "19") (term "0,1,0,1,0,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "19") (term "0,1,0,0,0,0,0")) - (rule "add_literals" (formula "19") (term "0,0,1,0,0,0,0,0")) - (rule "inEqSimp_sepNegMonomial0" (formula "19") (term "1,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "19") (term "0,1,0,0,0,0")) - (rule "polySimp_elimOne" (formula "19") (term "0,1,0,0,0,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "19") (term "1,0,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "19") (term "0,1,0,0,0,0,0")) - (rule "polySimp_elimOne" (formula "19") (term "0,1,0,0,0,0,0")) - (rule "inEqSimp_contradInEq0" (formula "19") (term "1,0,0,0,0") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "19") (term "0,1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "mul_literals" (formula "19") (term "0,1,0,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "polySimp_addComm0" (formula "19") (term "0,0,0,1,0,0,0,0")) - (rule "polySimp_pullOutFactor1b" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "1,1,0,0,1,0,0,0,0")) - (rule "times_zero_1" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "add_zero_right" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "leq_literals" (formula "19") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "19")) - (rule "inEqSimp_contradInEq1" (formula "19") (term "1,0,0,0,0") (ifseqformula "4")) - (rule "qeq_literals" (formula "19") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "19")) - (rule "allLeft" (formula "17") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1,0")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,0")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,0")) - (rule "add_literals" (formula "17") (term "0,0,1,0")) + (rule "allLeft" (formula "18") (inst "t=i_0:int")) + (rule "eqSymm" (formula "18") (term "1")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "1,0")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,1,0")) + (rule "add_literals" (formula "18") (term "1,1,0,1,0")) + (rule "times_zero_1" (formula "18") (term "1,0,1,0")) + (rule "add_literals" (formula "18") (term "0,1,0")) + (rule "leq_literals" (formula "18") (term "1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "applyEq" (formula "18") (term "1,1,1") (ifseqformula "25")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "3")) + (rule "qeq_literals" (formula "18") (term "0,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "replace_known_left" (formula "34") (term "1,0") (ifseqformula "18")) + (builtin "One Step Simplification" (formula "34")) + (rule "allLeft" (formula "17") (inst "t=i_0:int")) (rule "inEqSimp_homoInEq1" (formula "17") (term "1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1")) - (rule "polySimp_addComm1" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,0,1")) - (rule "add_zero_left" (formula "17") (term "0,0,1")) - (rule "inEqSimp_sepNegMonomial1" (formula "17") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "17") (term "0,1,0")) - (rule "inEqSimp_sepNegMonomial0" (formula "17") (term "1")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1")) - (rule "polySimp_elimOne" (formula "17") (term "0,1")) - (rule "inEqSimp_contradInEq0" (formula "17") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "0,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,0,1")) - (rule "polySimp_addComm0" (formula "17") (term "0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "17") (term "1,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "leq_literals" (formula "17") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,1")) + (rule "add_literals" (formula "17") (term "1,1,0,1")) + (rule "times_zero_1" (formula "17") (term "1,0,1")) + (rule "add_literals" (formula "17") (term "0,1")) + (rule "leq_literals" (formula "17") (term "1")) (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "4")) + (rule "applyEq" (formula "17") (term "0,0,0") (ifseqformula "26")) + (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "3")) (rule "qeq_literals" (formula "17") (term "0,1")) (builtin "One Step Simplification" (formula "17")) (rule "notLeft" (formula "17")) - (rule "referencedObjectIsCreatedRightEQ" (formula "33") (ifseqformula "23") (ifseqformula "30")) - (rule "close" (formula "33") (ifseqformula "12")) + (rule "replace_known_right" (formula "35") (term "0,0") (ifseqformula "28")) + (builtin "One Step Simplification" (formula "35")) + (rule "allRight" (formula "35") (inst "sk=j_0:int")) + (rule "orRight" (formula "35")) + (rule "orRight" (formula "35")) + (rule "orRight" (formula "37")) + (rule "notRight" (formula "37")) + (rule "inEqSimp_leqRight" (formula "36")) + (rule "mul_literals" (formula "1") (term "1,0,0")) + (rule "add_literals" (formula "1") (term "0,0")) + (rule "add_zero_left" (formula "1") (term "0")) + (rule "inEqSimp_geqRight" (formula "37")) + (rule "polySimp_rightDist" (formula "1") (term "1,0,0")) + (rule "mul_literals" (formula "1") (term "0,1,0,0")) + (rule "polySimp_addAssoc" (formula "1") (term "0,0")) + (rule "add_literals" (formula "1") (term "0,0,0")) + (rule "add_zero_left" (formula "1") (term "0,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "1")) + (rule "polySimp_mulLiterals" (formula "1") (term "1")) + (rule "polySimp_elimOne" (formula "1") (term "1")) + (rule "inEqSimp_strengthen0" (formula "1") (ifseqformula "38")) + (rule "inEqSimp_contradEq3" (formula "38") (ifseqformula "1")) + (rule "polySimp_mulComm0" (formula "38") (term "1,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "38") (term "0,0")) + (rule "add_literals" (formula "38") (term "1,1,0,0")) + (rule "times_zero_1" (formula "38") (term "1,0,0")) + (rule "add_literals" (formula "38") (term "0,0")) + (rule "qeq_literals" (formula "38") (term "0")) + (builtin "One Step Simplification" (formula "38")) + (rule "false_right" (formula "38")) + (rule "inEqSimp_exactShadow3" (formula "2") (ifseqformula "1")) + (rule "mul_literals" (formula "2") (term "0,0")) + (rule "add_zero_left" (formula "2") (term "0")) + (rule "inEqSimp_sepPosMonomial1" (formula "2")) + (rule "mul_literals" (formula "2") (term "1")) + (rule "allLeft" (formula "25") (inst "t=nv_0:int")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "25") (term "0,1,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq0" (formula "25") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,1")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,1")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,1")) + (rule "polySimp_addComm0" (formula "25") (term "0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,1")) + (rule "add_literals" (formula "25") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "25") (term "1,0,0,1")) + (rule "add_literals" (formula "25") (term "0,0,1")) + (rule "leq_literals" (formula "25") (term "0,1")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "26") (inst "t=Z(0(#)):int")) + (rule "add_literals" (formula "26") (term "1,1,0,0")) + (rule "leq_literals" (formula "26") (term "1,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "inEqSimp_commuteGeq" (formula "26") (term "1")) + (rule "applyEq" (formula "26") (term "1,0,0") (ifseqformula "29")) + (rule "eqSymm" (formula "26") (term "0")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "1") (ifseqformula "6")) + (rule "qeq_literals" (formula "26") (term "0,1")) + (builtin "One Step Simplification" (formula "26")) + (rule "allLeft" (formula "23") (inst "t=nv_0:int")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "23") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq0" (formula "23") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "23") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "23") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "23") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "22") (inst "t=nv_0:int")) + (rule "eqSymm" (formula "22") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "22") (term "0,0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "inEqSimp_contradInEq0" (formula "22") (term "0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "22") (term "0,0")) + (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "22") (term "1,0,0,0")) + (rule "mul_literals" (formula "22") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "22") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "22") (term "0,0,0,0")) + (rule "add_literals" (formula "22") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "22") (term "0,0,0")) + (rule "add_literals" (formula "22") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "22") (term "1,0,0,0")) + (rule "add_literals" (formula "22") (term "0,0,0")) + (rule "leq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "allLeft" (formula "20") (inst "t=nv_0:int")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq0" (formula "20") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "23") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "eqSymm" (formula "23") (term "1")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0")) + (rule "mul_literals" (formula "23") (term "1,0,0")) + (rule "add_zero_right" (formula "23") (term "0,0")) + (rule "applyEq" (formula "23") (term "1,1,1") (ifseqformula "32")) + (rule "inEqSimp_sepPosMonomial0" (formula "23") (term "0")) + (rule "mul_literals" (formula "23") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0") (ifseqformula "6")) + (rule "qeq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "20") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "20") (term "1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "1")) + (rule "mul_literals" (formula "20") (term "1,0,1")) + (rule "add_zero_right" (formula "20") (term "0,1")) + (rule "applyEq" (formula "20") (term "0,0,0") (ifseqformula "33")) + (rule "inEqSimp_sepPosMonomial0" (formula "20") (term "1")) + (rule "mul_literals" (formula "20") (term "1,1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "6")) + (rule "qeq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "replace_known_right" (formula "31") (term "0") (ifseqformula "36")) + (builtin "One Step Simplification" (formula "31")) + (rule "allLeft" (formula "24") (inst "t=i_0_0:int")) + (rule "eqSymm" (formula "24") (term "1")) + (rule "applyEq" (formula "24") (term "1,1,1") (ifseqformula "13")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0,0") (ifseqformula "11")) + (rule "qeq_literals" (formula "24") (term "0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "inEqSimp_contradInEq0" (formula "24") (term "0") (ifseqformula "12")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "24") (term "1,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0")) + (rule "leq_literals" (formula "24") (term "0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "allLeft" (formula "27") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_homoInEq0" (formula "27") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,1,0,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0,1,0,0,0,0")) + (rule "add_zero_left" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "27") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "27") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "27") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "27") (term "1,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_elimOne" (formula "27") (term "0,1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "27") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "inEqSimp_contradInEq0" (formula "27") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm0" (formula "27") (term "0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "27") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "allLeft" (formula "25") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "eqSymm" (formula "25") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "1,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,1,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,1,0")) + (rule "polySimp_addComm1" (formula "25") (term "0,0,1,0")) + (rule "add_literals" (formula "25") (term "0,0,0,1,0")) + (rule "add_zero_left" (formula "25") (term "0,0,1,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "25") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "25") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "25") (term "0,0,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "25") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "25") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "25") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "25") (term "0,0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq0" (formula "25") (term "0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "polySimp_addComm0" (formula "25") (term "0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "25") (term "1,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0")) + (rule "leq_literals" (formula "25") (term "0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,1")) + (rule "add_zero_left" (formula "20") (term "0,0,1")) + (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "20") (term "0,1,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "20") (term "1")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1")) + (rule "polySimp_elimOne" (formula "20") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq0" (formula "20") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm0" (formula "20") (term "0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "referencedObjectIsCreatedRightEQ" (formula "45") (ifseqformula "31") (ifseqformula "39")) + (rule "close" (formula "45") (ifseqformula "15")) ) ) ) @@ -1536,19 +1827,19 @@ (rule "leq_literals" (formula "29") (term "0")) (builtin "One Step Simplification" (formula "29")) (rule "false_right" (formula "29")) + (rule "all_pull_out1" (formula "19") (term "0,1,0")) (rule "ifthenelse_split" (formula "2") (term "0")) (branch "(Node)self.nodeseq[i_0] = n_2 TRUE" - (rule "applyEqReverse" (formula "30") (term "1,1") (ifseqformula "3")) + (rule "applyEqReverse" (formula "30") (term "1,1,0,0") (ifseqformula "3")) (rule "hideAuxiliaryEq" (formula "3")) (rule "replace_known_left" (formula "1") (term "0,0") (ifseqformula "2")) (builtin "One Step Simplification" (formula "1")) - (rule "applyEqReverse" (formula "29") (term "1,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "29") (term "1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "applyEq" (formula "28") (term "1,0,0,1,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "28") (term "0,0,0,0,0") (ifseqformula "1")) (rule "replace_known_right" (formula "28") (term "0,0,0,0") (ifseqformula "26")) (builtin "One Step Simplification" (formula "28")) - (rule "all_pull_out1" (formula "18") (term "0,1,0")) + (rule "applyEq" (formula "28") (term "1,0,0,1,0,1,0") (ifseqformula "1")) (rule "all_pull_out0" (formula "18") (term "1,0")) (rule "shift_paren_and" (formula "18") (term "0,1,0")) (rule "all_pull_out3" (formula "18") (term "0")) @@ -1592,10 +1883,10 @@ (builtin "One Step Simplification" (formula "19")) (rule "applyEq" (formula "19") (term "1,0,0") (ifseqformula "22")) (rule "inEqSimp_invertInEq1" (formula "19") (term "1")) - (rule "mul_literals" (formula "19") (term "1,1")) (rule "polySimp_mulLiterals" (formula "19") (term "0,1")) + (rule "mul_literals" (formula "19") (term "1,1")) (rule "polySimp_elimOne" (formula "19") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "19") (term "1") (ifseqformula "23")) + (rule "inEqSimp_contradInEq1" (formula "19") (term "1") (ifseqformula "24")) (rule "qeq_literals" (formula "19") (term "0,1")) (builtin "One Step Simplification" (formula "19")) (rule "cnf_rightDist" (formula "18") (term "0,0")) @@ -1613,8 +1904,8 @@ (rule "commute_or" (formula "18") (term "0,0")) (rule "commute_or_2" (formula "20") (term "0,0,0,0")) (rule "shift_paren_or" (formula "20") (term "0,0,0,0,0")) - (rule "cut_direct" (formula "8") (term "1,0")) - (branch "CUT: fv_0 = Node::#next TRUE" + (rule "cut_direct" (formula "8") (term "0,0")) + (branch "CUT: fv_0 = Node::#data TRUE" (builtin "One Step Simplification" (formula "9")) (rule "true_left" (formula "9")) (rule "seqGetAlphaCast" (formula "23") (term "0")) @@ -1626,7 +1917,7 @@ (builtin "One Step Simplification" (formula "24")) (rule "true_left" (formula "24")) (rule "onlyCreatedObjectsAreReferenced" (formula "23") (term "1") (ifseqformula "13")) - (rule "allLeft" (formula "22") (inst "t=i_0")) + (rule "allLeft" (formula "22") (inst "t=i_0:int")) (rule "inEqSimp_homoInEq1" (formula "22") (term "1")) (rule "polySimp_addComm1" (formula "22") (term "0,1")) (rule "applyEq" (formula "22") (term "1,0,0,0") (ifseqformula "1")) @@ -1634,9 +1925,12 @@ (rule "inEqSimp_sepPosMonomial0" (formula "22") (term "1")) (rule "polySimp_mulComm0" (formula "22") (term "1,1")) (rule "polySimp_rightDist" (formula "22") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "mul_literals" (formula "22") (term "0,1,1")) + (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "polySimp_elimOne" (formula "22") (term "1,1,1")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "1,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "22") (term "0,1,0")) + (builtin "One Step Simplification" (formula "22")) (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "3")) (rule "inEqSimp_homoInEq1" (formula "22") (term "0,1")) (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,1")) @@ -1651,11 +1945,8 @@ (rule "add_literals" (formula "22") (term "0,0,1")) (rule "leq_literals" (formula "22") (term "0,1")) (builtin "One Step Simplification" (formula "22")) - (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "2")) - (rule "qeq_literals" (formula "22") (term "0,1")) - (builtin "One Step Simplification" (formula "22")) (rule "applyEq" (formula "34") (term "0,1") (ifseqformula "22")) - (rule "allLeft" (formula "23") (inst "t=nv_0")) + (rule "allLeft" (formula "23") (inst "t=nv_0:int")) (rule "inEqSimp_homoInEq1" (formula "23") (term "1")) (rule "polySimp_addComm1" (formula "23") (term "0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "23") (term "1")) @@ -1681,7 +1972,343 @@ (rule "add_literals" (formula "23") (term "0,0,1")) (rule "leq_literals" (formula "23") (term "0,1")) (builtin "One Step Simplification" (formula "23")) - (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), nv_0)")) + (rule "seqGetAlphaCast" (formula "1") (term "0")) + (rule "castedGetAny" (formula "1") (term "0")) + (builtin "One Step Simplification" (formula "1")) + (rule "true_left" (formula "1")) + (rule "allLeft" (formula "19") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "19") (term "0,0")) + (builtin "One Step Simplification" (formula "19")) + (rule "eqSymm" (formula "19") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "19") (term "0")) + (rule "applyEq" (formula "19") (term "1,1,1") (ifseqformula "27")) + (rule "inEqSimp_contradInEq1" (formula "19") (term "0") (ifseqformula "30")) + (rule "qeq_literals" (formula "19") (term "0,0")) + (builtin "One Step Simplification" (formula "19")) + (rule "allLeft" (formula "20") (inst "t=i_0:int")) + (rule "eqSymm" (formula "20") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1,0")) + (rule "applyEq" (formula "20") (term "1,1,1") (ifseqformula "1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "20") (term "0,0,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,0")) + (rule "add_literals" (formula "20") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "20") (term "1,0,0,0")) + (rule "add_literals" (formula "20") (term "0,0,0")) + (rule "leq_literals" (formula "20") (term "0,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "applyEq" (formula "37") (term "0,0,0") (ifseqformula "20")) + (rule "allLeft" (formula "21") (inst "t=nv_0:int")) + (rule "eqSymm" (formula "21") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "21") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "21") (term "0,0,0")) + (builtin "One Step Simplification" (formula "21")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "21") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "21") (term "0,0,0")) + (rule "add_literals" (formula "21") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "21") (term "1,0,0,0")) + (rule "add_literals" (formula "21") (term "0,0,0")) + (rule "leq_literals" (formula "21") (term "0,0")) + (builtin "One Step Simplification" (formula "21")) + (rule "allLeft" (formula "23") (inst "t=i_0:int")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0,0,0,0")) + (rule "applyEq" (formula "23") (term "1,0,0,0,0,0,0,0") (ifseqformula "1")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "23") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "23") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "commute_or_2" (formula "23") (term "0")) + (rule "allLeft" (formula "24") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "24") (term "1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "1,0,0,0,0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "24") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "1,0,0,0,0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "24") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "24") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "24") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "commute_or_2" (formula "24") (term "0")) + (rule "allLeft" (formula "18") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "18") (term "1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) + (rule "applyEq" (formula "18") (term "0,0,0") (ifseqformula "32")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "35")) + (rule "qeq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "replace_known_right" (formula "30") (term "0") (ifseqformula "36")) + (builtin "One Step Simplification" (formula "30")) + (rule "allLeft" (formula "18") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "18") (term "0,1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,1")) + (rule "add_literals" (formula "18") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "18") (term "1,0,0,1")) + (rule "add_literals" (formula "18") (term "0,0,1")) + (rule "leq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "allLeft" (formula "22") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "eqSymm" (formula "22") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "22") (term "0,0")) + (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "22") (term "1,0,0,0")) + (rule "mul_literals" (formula "22") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "22") (term "0,0,0")) + (rule "add_literals" (formula "22") (term "0,0,0,0")) + (rule "add_zero_left" (formula "22") (term "0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "22") (term "1,0")) + (rule "polySimp_mulComm0" (formula "22") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "22") (term "1,0,1,0")) + (rule "mul_literals" (formula "22") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "22") (term "0,1,0")) + (rule "polySimp_addComm0" (formula "22") (term "0,0,1,0")) + (rule "polySimp_pullOutFactor1b" (formula "22") (term "0,1,0")) + (rule "add_literals" (formula "22") (term "1,1,0,1,0")) + (rule "times_zero_1" (formula "22") (term "1,0,1,0")) + (rule "add_literals" (formula "22") (term "0,1,0")) + (rule "leq_literals" (formula "22") (term "1,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "applyEq" (formula "22") (term "1,1,1") (ifseqformula "33")) + (rule "inEqSimp_invertInEq1" (formula "22") (term "0")) + (rule "polySimp_mulLiterals" (formula "22") (term "0,0")) + (rule "mul_literals" (formula "22") (term "1,0")) + (rule "polySimp_elimOne" (formula "22") (term "0,0")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "0") (ifseqformula "35")) + (rule "qeq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "allLeft" (formula "23") (inst "t=i_0_0:int")) + (rule "eqSymm" (formula "23") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0")) + (rule "applyEq" (formula "23") (term "1,1,1") (ifseqformula "11")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0,0") (ifseqformula "9")) + (rule "qeq_literals" (formula "23") (term "0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0") (ifseqformula "10")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,0")) + (rule "leq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "27") (inst "t=i_0_0:int")) + (rule "inEqSimp_commuteGeq" (formula "27") (term "1,0,0,0,0")) + (rule "applyEq" (formula "27") (term "1,0,0,0,0,0,0,0") (ifseqformula "11")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "1,0,0,0,0,0") (ifseqformula "9")) + (rule "qeq_literals" (formula "27") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "1,0,0,0,0") (ifseqformula "10")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "27") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "commute_or_2" (formula "27") (term "0")) + (rule "allLeft" (formula "18") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "inEqSimp_homoInEq0" (formula "18") (term "1,0")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,1,0")) + (rule "mul_literals" (formula "18") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "18") (term "0,1,0")) + (rule "add_literals" (formula "18") (term "0,0,1,0")) + (rule "add_zero_left" (formula "18") (term "0,1,0")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "1")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,1")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,1")) + (rule "mul_literals" (formula "18") (term "0,1,0,1")) + (rule "polySimp_addAssoc" (formula "18") (term "0,1")) + (rule "polySimp_addComm0" (formula "18") (term "0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,1")) + (rule "add_literals" (formula "18") (term "1,1,0,1")) + (rule "times_zero_1" (formula "18") (term "1,0,1")) + (rule "add_literals" (formula "18") (term "0,1")) + (rule "leq_literals" (formula "18") (term "1")) + (builtin "One Step Simplification" (formula "18")) + (rule "applyEq" (formula "18") (term "0,0,0") (ifseqformula "36")) + (rule "inEqSimp_invertInEq1" (formula "18") (term "1")) + (rule "polySimp_mulLiterals" (formula "18") (term "0,1")) + (rule "mul_literals" (formula "18") (term "1,1")) + (rule "polySimp_elimOne" (formula "18") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "38")) + (rule "qeq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "allLeft" (formula "24") (inst "t=add(Z(1(#)), i_0):int")) + (rule "eqSymm" (formula "24") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "24") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "24") (term "0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0,0")) + (rule "applyEq" (formula "24") (term "1,1,1") (ifseqformula "31")) + (rule "inEqSimp_sepNegMonomial1" (formula "24") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "24") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "24") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "24") (term "0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "24") (term "0,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "24") (term "1,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0")) + (rule "leq_literals" (formula "24") (term "0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "allLeft" (formula "25") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "eqSymm" (formula "25") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "25") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "25") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "25") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "25") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "25") (term "0,0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "25") (term "0,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "25") (term "1,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0")) + (rule "leq_literals" (formula "25") (term "0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "30") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "30") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "30") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "30") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "30") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "30") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "30") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "30") (term "0,0,1,0,0,0,0,0")) + (rule "applyEq" (formula "30") (term "1,0,0,0,0,0,0,0") (ifseqformula "33")) + (rule "inEqSimp_sepNegMonomial1" (formula "30") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "30") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "30") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "30") (term "1,0,0,0,0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "30") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "30")) + (rule "inEqSimp_contradInEq1" (formula "30") (term "1,0,0,0,0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "30") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "30") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "30") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "30") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "30") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "30") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "30") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "30") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "30") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "30") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "30") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "30") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "30")) + (rule "allLeft" (formula "31") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_commuteGeq" (formula "31") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "31") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "31") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "31") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "31") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "18") (term "1,0")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,1,0")) + (rule "mul_literals" (formula "18") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "18") (term "0,1,0")) + (rule "add_literals" (formula "18") (term "0,0,1,0")) + (rule "applyEq" (formula "18") (term "0,0,0,0") (ifseqformula "35")) + (rule "inEqSimp_sepNegMonomial1" (formula "18") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "18") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "18") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "18") (term "0,1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "0,1")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,0,1")) + (rule "mul_literals" (formula "18") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "18") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "18") (term "0,0,0,1")) + (rule "add_literals" (formula "18") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,1")) + (rule "add_literals" (formula "18") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "18") (term "1,0,0,1")) + (rule "add_literals" (formula "18") (term "0,0,1")) + (rule "leq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "replace_known_right" (formula "51") (term "1") (ifseqformula "43")) + (builtin "One Step Simplification" (formula "51")) + (rule "false_right" (formula "51")) + (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), nv_0):int")) (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) (rule "inEqSimp_homoInEq0" (formula "18") (term "1,0")) (rule "polySimp_mulComm0" (formula "18") (term "1,0,1,0")) @@ -1710,10 +2337,10 @@ (rule "leq_literals" (formula "18") (term "0,1")) (builtin "One Step Simplification" (formula "18")) (rule "notLeft" (formula "18")) - (rule "referencedObjectIsCreatedRightEQ" (formula "32") (ifseqformula "23") (ifseqformula "31")) - (rule "close" (formula "32") (ifseqformula "13")) + (rule "referencedObjectIsCreatedRightEQ" (formula "48") (ifseqformula "35") (ifseqformula "43")) + (rule "close" (formula "48") (ifseqformula "13")) ) - (branch "CUT: fv_0 = Node::#next FALSE" + (branch "CUT: fv_0 = Node::#data FALSE" (builtin "One Step Simplification" (formula "8")) (rule "seqGetAlphaCast" (formula "23") (term "0")) (rule "castedGetAny" (formula "23") (term "0")) @@ -1724,7 +2351,7 @@ (builtin "One Step Simplification" (formula "24")) (rule "true_left" (formula "24")) (rule "onlyCreatedObjectsAreReferenced" (formula "23") (term "1") (ifseqformula "13")) - (rule "allLeft" (formula "22") (inst "t=i_0")) + (rule "allLeft" (formula "22") (inst "t=i_0:int")) (rule "inEqSimp_homoInEq1" (formula "22") (term "1")) (rule "polySimp_addComm1" (formula "22") (term "0,1")) (rule "applyEq" (formula "22") (term "1,0,0,0") (ifseqformula "1")) @@ -1732,8 +2359,8 @@ (rule "inEqSimp_sepPosMonomial0" (formula "22") (term "1")) (rule "polySimp_mulComm0" (formula "22") (term "1,1")) (rule "polySimp_rightDist" (formula "22") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "mul_literals" (formula "22") (term "0,1,1")) + (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "polySimp_elimOne" (formula "22") (term "1,1,1")) (rule "inEqSimp_contradInEq1" (formula "22") (term "1,0") (ifseqformula "2")) (rule "qeq_literals" (formula "22") (term "0,1,0")) @@ -1753,7 +2380,7 @@ (rule "leq_literals" (formula "22") (term "0,1")) (builtin "One Step Simplification" (formula "22")) (rule "applyEq" (formula "35") (term "0,1") (ifseqformula "22")) - (rule "allLeft" (formula "23") (inst "t=nv_0")) + (rule "allLeft" (formula "23") (inst "t=nv_0:int")) (rule "inEqSimp_homoInEq1" (formula "23") (term "1")) (rule "polySimp_addComm1" (formula "23") (term "0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "23") (term "1")) @@ -1779,7 +2406,343 @@ (rule "add_literals" (formula "23") (term "0,0,1")) (rule "leq_literals" (formula "23") (term "0,1")) (builtin "One Step Simplification" (formula "23")) - (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), nv_0)")) + (rule "seqGetAlphaCast" (formula "1") (term "0")) + (rule "castedGetAny" (formula "1") (term "0")) + (builtin "One Step Simplification" (formula "1")) + (rule "true_left" (formula "1")) + (rule "allLeft" (formula "19") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "19") (term "0,0")) + (builtin "One Step Simplification" (formula "19")) + (rule "eqSymm" (formula "19") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "19") (term "0")) + (rule "applyEq" (formula "19") (term "1,1,1") (ifseqformula "27")) + (rule "inEqSimp_contradInEq1" (formula "19") (term "0") (ifseqformula "30")) + (rule "qeq_literals" (formula "19") (term "0,0")) + (builtin "One Step Simplification" (formula "19")) + (rule "allLeft" (formula "20") (inst "t=i_0:int")) + (rule "eqSymm" (formula "20") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1,0")) + (rule "applyEq" (formula "20") (term "1,1,1") (ifseqformula "1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "20") (term "0,0,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,0")) + (rule "add_literals" (formula "20") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "20") (term "1,0,0,0")) + (rule "add_literals" (formula "20") (term "0,0,0")) + (rule "leq_literals" (formula "20") (term "0,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "applyEq" (formula "38") (term "0,0,0") (ifseqformula "20")) + (rule "allLeft" (formula "21") (inst "t=nv_0:int")) + (rule "eqSymm" (formula "21") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "21") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "21") (term "0,0,0")) + (builtin "One Step Simplification" (formula "21")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "21") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "21") (term "0,0,0")) + (rule "add_literals" (formula "21") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "21") (term "1,0,0,0")) + (rule "add_literals" (formula "21") (term "0,0,0")) + (rule "leq_literals" (formula "21") (term "0,0")) + (builtin "One Step Simplification" (formula "21")) + (rule "allLeft" (formula "23") (inst "t=i_0:int")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0,0,0,0")) + (rule "applyEq" (formula "23") (term "1,0,0,0,0,0,0,0") (ifseqformula "1")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "23") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "23") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "commute_or_2" (formula "23") (term "0")) + (rule "allLeft" (formula "24") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "24") (term "1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "1,0,0,0,0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "24") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "1,0,0,0,0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "24") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "24") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "24") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "commute_or_2" (formula "24") (term "0")) + (rule "allLeft" (formula "18") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "18") (term "1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) + (rule "applyEq" (formula "18") (term "0,0,0") (ifseqformula "32")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "35")) + (rule "qeq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "replace_known_right" (formula "30") (term "0") (ifseqformula "36")) + (builtin "One Step Simplification" (formula "30")) + (rule "allLeft" (formula "18") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "18") (term "0,1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,1")) + (rule "add_literals" (formula "18") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "18") (term "1,0,0,1")) + (rule "add_literals" (formula "18") (term "0,0,1")) + (rule "leq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "allLeft" (formula "22") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "eqSymm" (formula "22") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "22") (term "0,0")) + (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "22") (term "1,0,0,0")) + (rule "mul_literals" (formula "22") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "22") (term "0,0,0")) + (rule "add_literals" (formula "22") (term "0,0,0,0")) + (rule "add_zero_left" (formula "22") (term "0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "22") (term "1,0")) + (rule "polySimp_mulComm0" (formula "22") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "22") (term "1,0,1,0")) + (rule "mul_literals" (formula "22") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "22") (term "0,1,0")) + (rule "polySimp_addComm0" (formula "22") (term "0,0,1,0")) + (rule "polySimp_pullOutFactor1b" (formula "22") (term "0,1,0")) + (rule "add_literals" (formula "22") (term "1,1,0,1,0")) + (rule "times_zero_1" (formula "22") (term "1,0,1,0")) + (rule "add_literals" (formula "22") (term "0,1,0")) + (rule "leq_literals" (formula "22") (term "1,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "applyEq" (formula "22") (term "1,1,1") (ifseqformula "33")) + (rule "inEqSimp_invertInEq1" (formula "22") (term "0")) + (rule "polySimp_mulLiterals" (formula "22") (term "0,0")) + (rule "mul_literals" (formula "22") (term "1,0")) + (rule "polySimp_elimOne" (formula "22") (term "0,0")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "0") (ifseqformula "35")) + (rule "qeq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "allLeft" (formula "23") (inst "t=i_0_0:int")) + (rule "eqSymm" (formula "23") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0")) + (rule "applyEq" (formula "23") (term "1,1,1") (ifseqformula "11")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0,0") (ifseqformula "9")) + (rule "qeq_literals" (formula "23") (term "0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0") (ifseqformula "10")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,0")) + (rule "leq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "27") (inst "t=i_0_0:int")) + (rule "inEqSimp_commuteGeq" (formula "27") (term "1,0,0,0,0")) + (rule "applyEq" (formula "27") (term "1,0,0,0,0,0,0,0") (ifseqformula "11")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "1,0,0,0,0,0") (ifseqformula "9")) + (rule "qeq_literals" (formula "27") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "1,0,0,0,0") (ifseqformula "10")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "27") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "27") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "commute_or_2" (formula "27") (term "0")) + (rule "allLeft" (formula "18") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "inEqSimp_homoInEq0" (formula "18") (term "1,0")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,1,0")) + (rule "mul_literals" (formula "18") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "18") (term "0,1,0")) + (rule "add_literals" (formula "18") (term "0,0,1,0")) + (rule "add_zero_left" (formula "18") (term "0,1,0")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "1")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,1")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,1")) + (rule "mul_literals" (formula "18") (term "0,1,0,1")) + (rule "polySimp_addAssoc" (formula "18") (term "0,1")) + (rule "polySimp_addComm0" (formula "18") (term "0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,1")) + (rule "add_literals" (formula "18") (term "1,1,0,1")) + (rule "times_zero_1" (formula "18") (term "1,0,1")) + (rule "add_literals" (formula "18") (term "0,1")) + (rule "leq_literals" (formula "18") (term "1")) + (builtin "One Step Simplification" (formula "18")) + (rule "applyEq" (formula "18") (term "0,0,0") (ifseqformula "36")) + (rule "inEqSimp_invertInEq1" (formula "18") (term "1")) + (rule "polySimp_mulLiterals" (formula "18") (term "0,1")) + (rule "mul_literals" (formula "18") (term "1,1")) + (rule "polySimp_elimOne" (formula "18") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "38")) + (rule "qeq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "allLeft" (formula "24") (inst "t=add(Z(1(#)), i_0):int")) + (rule "eqSymm" (formula "24") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "24") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "24") (term "0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0,0")) + (rule "applyEq" (formula "24") (term "1,1,1") (ifseqformula "31")) + (rule "inEqSimp_sepNegMonomial1" (formula "24") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "24") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "24") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "24") (term "0,0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "24") (term "0,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "24") (term "1,0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0")) + (rule "leq_literals" (formula "24") (term "0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "allLeft" (formula "25") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "eqSymm" (formula "25") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "25") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "25") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "25") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "25") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "25") (term "0,0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,0")) + (rule "polySimp_mulComm0" (formula "25") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "25") (term "1,0,0,0")) + (rule "mul_literals" (formula "25") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "25") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "25") (term "0,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "25") (term "1,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0")) + (rule "leq_literals" (formula "25") (term "0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "30") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "30") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "30") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "30") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "30") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "30") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "30") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "30") (term "0,0,1,0,0,0,0,0")) + (rule "applyEq" (formula "30") (term "1,0,0,0,0,0,0,0") (ifseqformula "33")) + (rule "inEqSimp_sepNegMonomial1" (formula "30") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "30") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "30") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "30") (term "1,0,0,0,0,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "30") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "30")) + (rule "inEqSimp_contradInEq1" (formula "30") (term "1,0,0,0,0") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "30") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "30") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "30") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "30") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "30") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "30") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "30") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "30") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "30") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "30") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "30") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "30") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "30")) + (rule "allLeft" (formula "31") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_commuteGeq" (formula "31") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0,0") (ifseqformula "5")) + (rule "qeq_literals" (formula "31") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0") (ifseqformula "4")) + (rule "inEqSimp_homoInEq1" (formula "31") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "31") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "31") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "18") (term "1,0")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,1,0")) + (rule "mul_literals" (formula "18") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "18") (term "0,1,0")) + (rule "add_literals" (formula "18") (term "0,0,1,0")) + (rule "applyEq" (formula "18") (term "0,0,0,0") (ifseqformula "35")) + (rule "inEqSimp_sepNegMonomial1" (formula "18") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "18") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "18") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1,0") (ifseqformula "2")) + (rule "qeq_literals" (formula "18") (term "0,1,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "3")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "0,1")) + (rule "polySimp_mulComm0" (formula "18") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "18") (term "1,0,0,1")) + (rule "mul_literals" (formula "18") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "18") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "18") (term "0,0,0,1")) + (rule "add_literals" (formula "18") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,1")) + (rule "add_literals" (formula "18") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "18") (term "1,0,0,1")) + (rule "add_literals" (formula "18") (term "0,0,1")) + (rule "leq_literals" (formula "18") (term "0,1")) + (builtin "One Step Simplification" (formula "18")) + (rule "notLeft" (formula "18")) + (rule "replace_known_right" (formula "52") (term "1") (ifseqformula "43")) + (builtin "One Step Simplification" (formula "52")) + (rule "false_right" (formula "52")) + (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), nv_0):int")) (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) (rule "inEqSimp_homoInEq0" (formula "18") (term "1,0")) (rule "polySimp_mulComm0" (formula "18") (term "1,0,1,0")) @@ -1808,19 +2771,18 @@ (rule "leq_literals" (formula "18") (term "0,1")) (builtin "One Step Simplification" (formula "18")) (rule "notLeft" (formula "18")) - (rule "referencedObjectIsCreatedRightEQ" (formula "33") (ifseqformula "23") (ifseqformula "31")) - (rule "close" (formula "33") (ifseqformula "13")) + (rule "referencedObjectIsCreatedRightEQ" (formula "49") (ifseqformula "35") (ifseqformula "43")) + (rule "close" (formula "49") (ifseqformula "13")) ) ) (branch "(Node)self.nodeseq[i_0] = n_2 FALSE" - (rule "applyEqReverse" (formula "30") (term "1,1") (ifseqformula "2")) + (rule "applyEqReverse" (formula "30") (term "1,1,0,0") (ifseqformula "2")) (rule "hideAuxiliaryEq" (formula "2")) - (rule "eqSymm" (formula "29") (term "1")) (rule "replace_known_right" (formula "1") (term "0,0") (ifseqformula "24")) (builtin "One Step Simplification" (formula "1")) - (rule "applyEqReverse" (formula "29") (term "1,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "29") (term "1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "all_pull_out1" (formula "17") (term "0,1,0")) + (rule "eqSymm" (formula "28") (term "1")) (rule "cut_direct" (formula "28") (term "0,0,0,0")) (branch "CUT: (Node)self.nodeseq[i_0] = null TRUE" (builtin "One Step Simplification" (formula "29")) @@ -1873,7 +2835,7 @@ (rule "polySimp_mulLiterals" (formula "19") (term "0,1")) (rule "mul_literals" (formula "19") (term "1,1")) (rule "polySimp_elimOne" (formula "19") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "19") (term "1") (ifseqformula "23")) + (rule "inEqSimp_contradInEq1" (formula "19") (term "1") (ifseqformula "24")) (rule "qeq_literals" (formula "19") (term "0,1")) (builtin "One Step Simplification" (formula "19")) (rule "cnf_rightDist" (formula "18") (term "0,0")) @@ -1891,8 +2853,8 @@ (rule "commute_or" (formula "18") (term "0,0")) (rule "commute_or_2" (formula "20") (term "0,0,0,0")) (rule "shift_paren_or" (formula "20") (term "0,0,0,0,0")) - (rule "cut_direct" (formula "8") (term "1,0")) - (branch "CUT: fv_0 = Node::#next TRUE" + (rule "cut_direct" (formula "8") (term "0,0")) + (branch "CUT: fv_0 = Node::#data TRUE" (builtin "One Step Simplification" (formula "9")) (rule "true_left" (formula "9")) (rule "seqGetAlphaCast" (formula "23") (term "0")) @@ -1904,24 +2866,24 @@ (builtin "One Step Simplification" (formula "24")) (rule "true_left" (formula "24")) (rule "onlyCreatedObjectsAreReferenced" (formula "23") (term "1") (ifseqformula "13")) - (rule "allLeft" (formula "18") (inst "t=i_0")) + (rule "allLeft" (formula "18") (inst "t=i_0:int")) (rule "replace_known_left" (formula "18") (term "0,0,0") (ifseqformula "1")) (builtin "One Step Simplification" (formula "18")) (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "2")) (rule "qeq_literals" (formula "18") (term "0,0")) (builtin "One Step Simplification" (formula "18")) - (rule "inEqSimp_contradInEq0" (formula "3") (ifseqformula "18")) - (rule "andLeft" (formula "3")) - (rule "inEqSimp_homoInEq1" (formula "3")) - (rule "polySimp_pullOutFactor1b" (formula "3") (term "0")) - (rule "add_literals" (formula "3") (term "1,1,0")) - (rule "times_zero_1" (formula "3") (term "1,0")) - (rule "add_literals" (formula "3") (term "0")) - (rule "leq_literals" (formula "3")) - (rule "closeFalse" (formula "3")) + (rule "inEqSimp_contradInEq1" (formula "18") (ifseqformula "3")) + (rule "andLeft" (formula "18")) + (rule "inEqSimp_homoInEq1" (formula "18")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0")) + (rule "add_literals" (formula "18") (term "1,1,0")) + (rule "times_zero_1" (formula "18") (term "1,0")) + (rule "add_literals" (formula "18") (term "0")) + (rule "leq_literals" (formula "18")) + (rule "closeFalse" (formula "18")) ) - (branch "CUT: fv_0 = Node::#next FALSE" + (branch "CUT: fv_0 = Node::#data FALSE" (builtin "One Step Simplification" (formula "8")) (rule "seqGetAlphaCast" (formula "23") (term "0")) (rule "castedGetAny" (formula "23") (term "0")) @@ -1932,22 +2894,22 @@ (builtin "One Step Simplification" (formula "24")) (rule "true_left" (formula "24")) (rule "onlyCreatedObjectsAreReferenced" (formula "23") (term "1") (ifseqformula "13")) - (rule "allLeft" (formula "18") (inst "t=i_0")) + (rule "allLeft" (formula "18") (inst "t=i_0:int")) (rule "replace_known_left" (formula "18") (term "0,0,0") (ifseqformula "1")) (builtin "One Step Simplification" (formula "18")) (rule "inEqSimp_commuteGeq" (formula "18") (term "1")) - (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "3")) - (rule "inEqSimp_homoInEq1" (formula "18") (term "0,1")) - (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,1")) - (rule "add_literals" (formula "18") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "18") (term "1,0,0,1")) - (rule "add_literals" (formula "18") (term "0,0,1")) - (rule "leq_literals" (formula "18") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "2")) + (rule "qeq_literals" (formula "18") (term "0,0")) (builtin "One Step Simplification" (formula "18")) - (rule "inEqSimp_contradInEq0" (formula "2") (ifseqformula "18")) - (rule "qeq_literals" (formula "2") (term "0")) - (builtin "One Step Simplification" (formula "2")) - (rule "closeFalse" (formula "2")) + (rule "inEqSimp_contradInEq1" (formula "18") (ifseqformula "3")) + (rule "andLeft" (formula "18")) + (rule "inEqSimp_homoInEq1" (formula "18")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0")) + (rule "add_literals" (formula "18") (term "1,1,0")) + (rule "times_zero_1" (formula "18") (term "1,0")) + (rule "add_literals" (formula "18") (term "0")) + (rule "leq_literals" (formula "18")) + (rule "closeFalse" (formula "18")) ) ) (branch "CUT: (Node)self.nodeseq[i_0] = null FALSE" @@ -1995,10 +2957,10 @@ (builtin "One Step Simplification" (formula "18")) (rule "applyEq" (formula "18") (term "1,0,0") (ifseqformula "21")) (rule "inEqSimp_invertInEq1" (formula "18") (term "1")) - (rule "mul_literals" (formula "18") (term "1,1")) (rule "polySimp_mulLiterals" (formula "18") (term "0,1")) + (rule "mul_literals" (formula "18") (term "1,1")) (rule "polySimp_elimOne" (formula "18") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "22")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "23")) (rule "qeq_literals" (formula "18") (term "0,1")) (builtin "One Step Simplification" (formula "18")) (rule "cnf_rightDist" (formula "17") (term "0,0")) @@ -2016,8 +2978,8 @@ (rule "commute_or" (formula "17") (term "0,0")) (rule "commute_or_2" (formula "19") (term "0,0,0,0")) (rule "shift_paren_or" (formula "19") (term "0,0,0,0,0")) - (rule "cut_direct" (formula "7") (term "1,0")) - (branch "CUT: fv_0 = Node::#next TRUE" + (rule "cut_direct" (formula "7") (term "0,0")) + (branch "CUT: fv_0 = Node::#data TRUE" (builtin "One Step Simplification" (formula "8")) (rule "true_left" (formula "8")) (rule "seqGetAlphaCast" (formula "22") (term "0")) @@ -2029,19 +2991,19 @@ (builtin "One Step Simplification" (formula "23")) (rule "true_left" (formula "23")) (rule "onlyCreatedObjectsAreReferenced" (formula "22") (term "1") (ifseqformula "12")) - (rule "allLeft" (formula "21") (inst "t=nv_0")) + (rule "allLeft" (formula "21") (inst "t=i_0:int")) (rule "inEqSimp_homoInEq1" (formula "21") (term "1")) (rule "polySimp_addComm1" (formula "21") (term "0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1")) (rule "polySimp_mulComm0" (formula "21") (term "1,1")) (rule "polySimp_rightDist" (formula "21") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1")) (rule "mul_literals" (formula "21") (term "0,1,1")) + (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1")) (rule "polySimp_elimOne" (formula "21") (term "1,1,1")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1,0") (ifseqformula "4")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "1,0") (ifseqformula "1")) (rule "qeq_literals" (formula "21") (term "0,1,0")) (builtin "One Step Simplification" (formula "21")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1") (ifseqformula "3")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "1") (ifseqformula "2")) (rule "inEqSimp_homoInEq1" (formula "21") (term "0,1")) (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1")) (rule "polySimp_rightDist" (formula "21") (term "1,0,0,1")) @@ -2055,7 +3017,9 @@ (rule "add_literals" (formula "21") (term "0,0,1")) (rule "leq_literals" (formula "21") (term "0,1")) (builtin "One Step Simplification" (formula "21")) - (rule "allLeft" (formula "22") (inst "t=i_0")) + (rule "replace_known_left" (formula "35") (term "1") (ifseqformula "21")) + (builtin "One Step Simplification" (formula "35")) + (rule "allLeft" (formula "22") (inst "t=nv_0:int")) (rule "inEqSimp_homoInEq1" (formula "22") (term "1")) (rule "polySimp_addComm1" (formula "22") (term "0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "22") (term "1")) @@ -2064,10 +3028,10 @@ (rule "mul_literals" (formula "22") (term "0,1,1")) (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "polySimp_elimOne" (formula "22") (term "1,1,1")) - (rule "inEqSimp_contradInEq1" (formula "22") (term "1,0") (ifseqformula "1")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "1,0") (ifseqformula "4")) (rule "qeq_literals" (formula "22") (term "0,1,0")) (builtin "One Step Simplification" (formula "22")) - (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "2")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "3")) (rule "inEqSimp_homoInEq1" (formula "22") (term "0,1")) (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,1")) (rule "polySimp_rightDist" (formula "22") (term "1,0,0,1")) @@ -2081,207 +3045,368 @@ (rule "add_literals" (formula "22") (term "0,0,1")) (rule "leq_literals" (formula "22") (term "0,1")) (builtin "One Step Simplification" (formula "22")) - (rule "replace_known_left" (formula "36") (term "1") (ifseqformula "22")) - (builtin "One Step Simplification" (formula "36")) - (rule "allLeft" (formula "19") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_commuteGeq" (formula "19") (term "1,0,0,0,0")) - (rule "inEqSimp_homoInEq0" (formula "19") (term "1,0,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "19") (term "1,0,1,0,0,0,0,0")) - (rule "polySimp_rightDist" (formula "19") (term "1,0,1,0,0,0,0,0")) - (rule "mul_literals" (formula "19") (term "0,1,0,1,0,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "19") (term "0,1,0,0,0,0,0")) - (rule "add_literals" (formula "19") (term "0,0,1,0,0,0,0,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "19") (term "1,0,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "19") (term "0,1,0,0,0,0,0")) - (rule "polySimp_elimOne" (formula "19") (term "0,1,0,0,0,0,0")) - (rule "inEqSimp_contradInEq1" (formula "19") (term "1,0,0,0,0,0") (ifseqformula "4")) - (rule "qeq_literals" (formula "19") (term "0,1,0,0,0,0,0")) - (builtin "One Step Simplification" (formula "19")) - (rule "inEqSimp_contradInEq1" (formula "19") (term "1,0,0,0,0") (ifseqformula "3")) - (rule "inEqSimp_homoInEq1" (formula "19") (term "0,1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "mul_literals" (formula "19") (term "0,1,0,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "polySimp_addComm1" (formula "19") (term "0,0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "0,0,0,0,1,0,0,0,0")) - (rule "polySimp_pullOutFactor1b" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "19") (term "1,1,0,0,1,0,0,0,0")) - (rule "times_zero_1" (formula "19") (term "1,0,0,1,0,0,0,0")) - (rule "add_zero_right" (formula "19") (term "0,0,1,0,0,0,0")) - (rule "leq_literals" (formula "19") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "19")) - (rule "commute_or_2" (formula "19") (term "0")) - (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), i_0)")) - (rule "inEqSimp_commuteGeq" (formula "20") (term "1,0,0,0,0")) - (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0,0,0,0,0")) - (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0,0,0,0,0")) - (rule "mul_literals" (formula "20") (term "0,1,0,1,0,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "20") (term "0,1,0,0,0,0,0")) - (rule "add_literals" (formula "20") (term "0,0,1,0,0,0,0,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0,0,0,0,0")) - (rule "polySimp_elimOne" (formula "20") (term "0,1,0,0,0,0,0")) - (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0,0,0,0,0") (ifseqformula "1")) - (rule "qeq_literals" (formula "20") (term "0,1,0,0,0,0,0")) - (builtin "One Step Simplification" (formula "20")) - (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0,0,0,0") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1,0,0,0,0")) - (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1,0,0,0,0")) - (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1,0,0,0,0")) - (rule "mul_literals" (formula "20") (term "0,1,0,0,1,0,0,0,0")) - (rule "polySimp_addAssoc" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1,0,0,0,0")) - (rule "add_literals" (formula "20") (term "0,0,0,0,1,0,0,0,0")) - (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "20") (term "1,1,0,0,1,0,0,0,0")) - (rule "times_zero_1" (formula "20") (term "1,0,0,1,0,0,0,0")) - (rule "add_zero_right" (formula "20") (term "0,0,1,0,0,0,0")) - (rule "leq_literals" (formula "20") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "20")) - (rule "commute_or_2" (formula "20") (term "0")) - (rule "allLeft" (formula "21") (inst "t=i_0")) - (rule "inEqSimp_commuteGeq" (formula "21") (term "1,0,0,0,0")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1,0,0,0,0,0") (ifseqformula "1")) - (rule "qeq_literals" (formula "21") (term "0,1,0,0,0,0,0")) - (builtin "One Step Simplification" (formula "21")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1,0,0,0,0") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "21") (term "0,1,0,0,0,0")) - (rule "polySimp_pullOutFactor1b" (formula "21") (term "0,0,1,0,0,0,0")) - (rule "add_literals" (formula "21") (term "1,1,0,0,1,0,0,0,0")) - (rule "times_zero_1" (formula "21") (term "1,0,0,1,0,0,0,0")) - (rule "add_zero_right" (formula "21") (term "0,0,1,0,0,0,0")) - (rule "leq_literals" (formula "21") (term "0,1,0,0,0,0")) - (builtin "One Step Simplification" (formula "21")) - (rule "commute_or_2" (formula "21") (term "0")) - (rule "allLeft" (formula "17") (inst "t=add(Z(1(#)), i_0)")) - (rule "inEqSimp_commuteGeq" (formula "17") (term "1")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1,0")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,0")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,0")) - (rule "add_literals" (formula "17") (term "0,0,1,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "17") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "17") (term "0,1,0")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "0,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,0,1")) - (rule "polySimp_addComm1" (formula "17") (term "0,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "17") (term "1,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "leq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "1")) - (rule "qeq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "notLeft" (formula "17")) - (rule "allLeft" (formula "17") (inst "t=add(Z(neglit(1(#))), - select<[int]>(heap, self, LinkedList::#size))")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1")) - (rule "polySimp_addComm0" (formula "17") (term "0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,1")) - (rule "add_literals" (formula "17") (term "1,1,0,1")) - (rule "times_zero_1" (formula "17") (term "1,0,1")) - (rule "add_zero_right" (formula "17") (term "0,1")) - (rule "leq_literals" (formula "17") (term "1")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "add_zero_left" (formula "17") (term "0,1")) - (rule "applyEq" (formula "17") (term "0,0,0") (ifseqformula "30")) - (rule "inEqSimp_invertInEq1" (formula "17") (term "1")) - (rule "mul_literals" (formula "17") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1")) - (rule "polySimp_elimOne" (formula "17") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "31")) - (rule "qeq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "notLeft" (formula "17")) - (rule "allLeft" (formula "17") (inst "t=i_0_0")) - (rule "inEqSimp_commuteGeq" (formula "17") (term "1")) - (rule "applyEq" (formula "17") (term "0,0,0,0") (ifseqformula "10")) - (rule "replace_known_right" (formula "17") (term "0,0,0") (ifseqformula "39")) - (builtin "One Step Simplification" (formula "17")) - (rule "true_left" (formula "17")) - (rule "allLeft" (formula "18") (inst "t=add(Z(1(#)), i_0)")) + (rule "seqGetAlphaCast" (formula "30") (term "0")) + (rule "castedGetAny" (formula "1") (term "0")) + (builtin "One Step Simplification" (formula "1")) + (rule "true_left" (formula "1")) + (rule "allLeft" (formula "18") (inst "t=i_0:int")) (rule "eqSymm" (formula "18") (term "1")) (rule "inEqSimp_commuteGeq" (formula "18") (term "1,0")) - (rule "inEqSimp_homoInEq0" (formula "18") (term "0,0")) - (rule "polySimp_mulComm0" (formula "18") (term "1,0,0,0")) - (rule "polySimp_rightDist" (formula "18") (term "1,0,0,0")) - (rule "mul_literals" (formula "18") (term "0,1,0,0,0")) - (rule "polySimp_addAssoc" (formula "18") (term "0,0,0")) - (rule "add_literals" (formula "18") (term "0,0,0,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "18") (term "0,0")) - (rule "polySimp_mulLiterals" (formula "18") (term "0,0,0")) - (rule "polySimp_elimOne" (formula "18") (term "0,0,0")) - (rule "inEqSimp_contradInEq1" (formula "18") (term "1,0") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "18") (term "0,1,0")) - (rule "polySimp_mulComm0" (formula "18") (term "1,0,0,1,0")) - (rule "polySimp_rightDist" (formula "18") (term "1,0,0,1,0")) - (rule "mul_literals" (formula "18") (term "0,1,0,0,1,0")) - (rule "polySimp_addAssoc" (formula "18") (term "0,0,1,0")) - (rule "polySimp_addComm1" (formula "18") (term "0,0,0,1,0")) - (rule "add_literals" (formula "18") (term "0,0,0,0,1,0")) - (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,1,0")) - (rule "add_literals" (formula "18") (term "1,1,0,0,1,0")) - (rule "times_zero_1" (formula "18") (term "1,0,0,1,0")) - (rule "add_zero_right" (formula "18") (term "0,0,1,0")) - (rule "leq_literals" (formula "18") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0,0") (ifseqformula "1")) + (rule "qeq_literals" (formula "18") (term "0,0,0")) (builtin "One Step Simplification" (formula "18")) - (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "1")) - (rule "qeq_literals" (formula "18") (term "0,0")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "2")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,0")) + (rule "add_literals" (formula "18") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "18") (term "1,0,0,0")) + (rule "add_literals" (formula "18") (term "0,0,0")) + (rule "leq_literals" (formula "18") (term "0,0")) (builtin "One Step Simplification" (formula "18")) - (rule "allLeft" (formula "17") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_commuteGeq" (formula "17") (term "1")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1,0")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,0")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,0")) - (rule "add_literals" (formula "17") (term "0,0,1,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "17") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "17") (term "0,1,0")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "3")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "0,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,0,1")) - (rule "polySimp_addComm1" (formula "17") (term "0,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "17") (term "1,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "leq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "notLeft" (formula "17")) - (rule "referencedObjectIsCreatedRightEQ" (formula "38") (ifseqformula "25") (ifseqformula "34")) - (rule "close" (formula "38") (ifseqformula "12")) + (rule "replace_known_left" (formula "37") (term "0") (ifseqformula "18")) + (builtin "One Step Simplification" (formula "37")) + (rule "allRight" (formula "37") (inst "sk=j_0:int")) + (rule "orRight" (formula "37")) + (rule "orRight" (formula "38")) + (rule "orRight" (formula "37")) + (rule "notRight" (formula "39")) + (rule "inEqSimp_geqRight" (formula "39")) + (rule "polySimp_mulComm0" (formula "1") (term "1,0,0")) + (rule "polySimp_addComm1" (formula "1") (term "0")) + (rule "inEqSimp_leqRight" (formula "39")) + (rule "mul_literals" (formula "1") (term "1,0,0")) + (rule "add_literals" (formula "1") (term "0,0")) + (rule "add_zero_left" (formula "1") (term "0")) + (rule "inEqSimp_sepNegMonomial0" (formula "2")) + (rule "polySimp_mulLiterals" (formula "2") (term "0")) + (rule "polySimp_elimOne" (formula "2") (term "0")) + (rule "allLeft" (formula "23") (inst "t=i_0:int")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "23") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "23") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "commute_or_2" (formula "23") (term "0")) + (rule "allLeft" (formula "22") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "eqSymm" (formula "22") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "22") (term "0")) + (rule "applyEq" (formula "22") (term "1,1,1") (ifseqformula "31")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "0") (ifseqformula "34")) + (rule "qeq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "allLeft" (formula "23") (inst "t=nv_0:int")) + (rule "eqSymm" (formula "23") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "23") (term "0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,0")) + (rule "leq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "26") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "26") (term "1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "26") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "1,0,0,0,0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "26") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "26") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "26") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "26") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "26") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "commute_or_2" (formula "26") (term "0")) + (rule "allLeft" (formula "20") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "20") (term "1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "applyEq" (formula "20") (term "0,0,0") (ifseqformula "34")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "37")) + (rule "qeq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "replace_known_right" (formula "32") (term "0") (ifseqformula "38")) + (builtin "One Step Simplification" (formula "32")) + (rule "allLeft" (formula "20") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "24") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "eqSymm" (formula "24") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "24") (term "0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0,0")) + (rule "add_zero_left" (formula "24") (term "0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "1,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,1,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,1,0")) + (rule "polySimp_addComm0" (formula "24") (term "0,0,1,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,1,0")) + (rule "add_literals" (formula "24") (term "1,1,0,1,0")) + (rule "times_zero_1" (formula "24") (term "1,0,1,0")) + (rule "add_literals" (formula "24") (term "0,1,0")) + (rule "leq_literals" (formula "24") (term "1,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "applyEq" (formula "24") (term "1,1,1") (ifseqformula "35")) + (rule "inEqSimp_invertInEq1" (formula "24") (term "0")) + (rule "polySimp_mulLiterals" (formula "24") (term "0,0")) + (rule "mul_literals" (formula "24") (term "1,0")) + (rule "polySimp_elimOne" (formula "24") (term "0,0")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0") (ifseqformula "37")) + (rule "qeq_literals" (formula "24") (term "0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "allLeft" (formula "25") (inst "t=i_0_0:int")) + (rule "eqSymm" (formula "25") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "25") (term "1,0")) + (rule "applyEq" (formula "25") (term "1,1,1") (ifseqformula "13")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0,0") (ifseqformula "11")) + (rule "qeq_literals" (formula "25") (term "0,0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0") (ifseqformula "12")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "25") (term "1,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0")) + (rule "leq_literals" (formula "25") (term "0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "20") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "add_zero_left" (formula "20") (term "0,1,0")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1")) + (rule "polySimp_addComm0" (formula "20") (term "0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,1")) + (rule "add_literals" (formula "20") (term "0,1")) + (rule "leq_literals" (formula "20") (term "1")) + (builtin "One Step Simplification" (formula "20")) + (rule "applyEq" (formula "20") (term "0,0,0") (ifseqformula "37")) + (rule "inEqSimp_invertInEq1" (formula "20") (term "1")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1")) + (rule "mul_literals" (formula "20") (term "1,1")) + (rule "polySimp_elimOne" (formula "20") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "39")) + (rule "qeq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "26") (inst "t=add(Z(1(#)), i_0):int")) + (rule "eqSymm" (formula "26") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "26") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "26") (term "0,0")) + (rule "polySimp_mulComm0" (formula "26") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "26") (term "1,0,0,0")) + (rule "mul_literals" (formula "26") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "26") (term "0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "26") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "26") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "26") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "0,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "26") (term "0,0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "26") (term "0,0")) + (rule "polySimp_mulComm0" (formula "26") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "26") (term "1,0,0,0")) + (rule "mul_literals" (formula "26") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "26") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "26") (term "0,0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "26") (term "0,0,0")) + (rule "add_literals" (formula "26") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "26") (term "1,0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,0")) + (rule "leq_literals" (formula "26") (term "0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "allLeft" (formula "27") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "eqSymm" (formula "27") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "27") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "27") (term "0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "27") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "27") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "27") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "27") (term "0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "27") (term "0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "27") (term "0,0,0")) + (rule "add_literals" (formula "27") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "27") (term "1,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0")) + (rule "leq_literals" (formula "27") (term "0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "allLeft" (formula "31") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "31") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "31") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "31") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "31") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "31") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "allLeft" (formula "32") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_commuteGeq" (formula "32") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "32") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "32") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "32") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "32") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "32") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "32") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "32") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "32") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "32") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "32") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "32") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "32")) + (rule "inEqSimp_contradInEq1" (formula "32") (term "1,0,0,0,0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "32") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "32") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "32") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "32") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "32") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "32") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "32") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "32") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "32") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "32") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "32") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "32") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "32")) + (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "20") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "20") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "referencedObjectIsCreatedRightEQ" (formula "50") (ifseqformula "36") (ifseqformula "44")) + (rule "close" (formula "50") (ifseqformula "15")) ) - (branch "CUT: fv_0 = Node::#next FALSE" + (branch "CUT: fv_0 = Node::#data FALSE" (builtin "One Step Simplification" (formula "7")) (rule "seqGetAlphaCast" (formula "22") (term "0")) (rule "castedGetAny" (formula "22") (term "0")) @@ -2292,15 +3417,18 @@ (builtin "One Step Simplification" (formula "23")) (rule "true_left" (formula "23")) (rule "onlyCreatedObjectsAreReferenced" (formula "22") (term "1") (ifseqformula "12")) - (rule "allLeft" (formula "21") (inst "t=i_0")) + (rule "allLeft" (formula "21") (inst "t=i_0:int")) (rule "inEqSimp_homoInEq1" (formula "21") (term "1")) (rule "polySimp_addComm1" (formula "21") (term "0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1")) (rule "polySimp_mulComm0" (formula "21") (term "1,1")) (rule "polySimp_rightDist" (formula "21") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1")) (rule "mul_literals" (formula "21") (term "0,1,1")) + (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1")) (rule "polySimp_elimOne" (formula "21") (term "1,1,1")) + (rule "inEqSimp_contradInEq1" (formula "21") (term "1,0") (ifseqformula "1")) + (rule "qeq_literals" (formula "21") (term "0,1,0")) + (builtin "One Step Simplification" (formula "21")) (rule "inEqSimp_contradInEq1" (formula "21") (term "1") (ifseqformula "2")) (rule "inEqSimp_homoInEq1" (formula "21") (term "0,1")) (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1")) @@ -2315,20 +3443,20 @@ (rule "add_literals" (formula "21") (term "0,0,1")) (rule "leq_literals" (formula "21") (term "0,1")) (builtin "One Step Simplification" (formula "21")) - (rule "inEqSimp_contradInEq1" (formula "21") (term "1") (ifseqformula "1")) - (rule "qeq_literals" (formula "21") (term "0,1")) - (builtin "One Step Simplification" (formula "21")) (rule "replace_known_left" (formula "36") (term "1") (ifseqformula "21")) (builtin "One Step Simplification" (formula "36")) - (rule "allLeft" (formula "22") (inst "t=nv_0")) + (rule "allLeft" (formula "22") (inst "t=nv_0:int")) (rule "inEqSimp_homoInEq1" (formula "22") (term "1")) (rule "polySimp_addComm1" (formula "22") (term "0,1")) (rule "inEqSimp_sepPosMonomial0" (formula "22") (term "1")) (rule "polySimp_mulComm0" (formula "22") (term "1,1")) (rule "polySimp_rightDist" (formula "22") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "mul_literals" (formula "22") (term "0,1,1")) + (rule "polySimp_mulLiterals" (formula "22") (term "1,1,1")) (rule "polySimp_elimOne" (formula "22") (term "1,1,1")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "1,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "22") (term "0,1,0")) + (builtin "One Step Simplification" (formula "22")) (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "3")) (rule "inEqSimp_homoInEq1" (formula "22") (term "0,1")) (rule "polySimp_mulComm0" (formula "22") (term "1,0,0,1")) @@ -2343,40 +3471,366 @@ (rule "add_literals" (formula "22") (term "0,0,1")) (rule "leq_literals" (formula "22") (term "0,1")) (builtin "One Step Simplification" (formula "22")) - (rule "inEqSimp_contradInEq1" (formula "22") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "22") (term "0,1")) + (rule "seqGetAlphaCast" (formula "31") (term "0")) + (rule "castedGetAny" (formula "1") (term "0")) + (builtin "One Step Simplification" (formula "1")) + (rule "true_left" (formula "1")) + (rule "allLeft" (formula "18") (inst "t=i_0:int")) + (rule "eqSymm" (formula "18") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "18") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0,0") (ifseqformula "1")) + (rule "qeq_literals" (formula "18") (term "0,0,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "inEqSimp_contradInEq1" (formula "18") (term "0") (ifseqformula "2")) + (rule "inEqSimp_homoInEq1" (formula "18") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,0,0")) + (rule "add_literals" (formula "18") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "18") (term "1,0,0,0")) + (rule "add_literals" (formula "18") (term "0,0,0")) + (rule "leq_literals" (formula "18") (term "0,0")) + (builtin "One Step Simplification" (formula "18")) + (rule "replace_known_left" (formula "38") (term "0") (ifseqformula "18")) + (builtin "One Step Simplification" (formula "38")) + (rule "allRight" (formula "38") (inst "sk=j_0:int")) + (rule "orRight" (formula "38")) + (rule "orRight" (formula "39")) + (rule "orRight" (formula "38")) + (rule "notRight" (formula "40")) + (rule "inEqSimp_geqRight" (formula "40")) + (rule "polySimp_mulComm0" (formula "1") (term "1,0,0")) + (rule "polySimp_addComm1" (formula "1") (term "0")) + (rule "inEqSimp_leqRight" (formula "40")) + (rule "mul_literals" (formula "1") (term "1,0,0")) + (rule "add_literals" (formula "1") (term "0,0")) + (rule "add_zero_left" (formula "1") (term "0")) + (rule "inEqSimp_sepNegMonomial0" (formula "2")) + (rule "polySimp_mulLiterals" (formula "2") (term "0")) + (rule "polySimp_elimOne" (formula "2") (term "0")) + (rule "allLeft" (formula "23") (inst "t=i_0:int")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "23") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "23") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "commute_or_2" (formula "23") (term "0")) + (rule "allLeft" (formula "22") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "22") (term "0,0")) + (builtin "One Step Simplification" (formula "22")) + (rule "eqSymm" (formula "22") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "22") (term "0")) + (rule "applyEq" (formula "22") (term "1,1,1") (ifseqformula "31")) + (rule "inEqSimp_contradInEq1" (formula "22") (term "0") (ifseqformula "34")) + (rule "qeq_literals" (formula "22") (term "0,0")) (builtin "One Step Simplification" (formula "22")) - (rule "allLeft" (formula "17") (inst "t=add(Z(1(#)), nv_0)")) - (rule "inEqSimp_commuteGeq" (formula "17") (term "1")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1,0")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,0")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,0")) - (rule "add_literals" (formula "17") (term "0,0,1,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "17") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "17") (term "0,1,0")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "3")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "0,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,0,1")) - (rule "polySimp_addComm1" (formula "17") (term "0,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "17") (term "1,0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "leq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "notLeft" (formula "17")) - (rule "referencedObjectIsCreatedRightEQ" (formula "33") (ifseqformula "22") (ifseqformula "30")) - (rule "close" (formula "33") (ifseqformula "12")) + (rule "allLeft" (formula "23") (inst "t=nv_0:int")) + (rule "eqSymm" (formula "23") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "23") (term "1,0")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "23") (term "0,0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "inEqSimp_contradInEq1" (formula "23") (term "0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "23") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "23") (term "0,0,0")) + (rule "add_literals" (formula "23") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "23") (term "1,0,0,0")) + (rule "add_literals" (formula "23") (term "0,0,0")) + (rule "leq_literals" (formula "23") (term "0,0")) + (builtin "One Step Simplification" (formula "23")) + (rule "allLeft" (formula "26") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "26") (term "1,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "26") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "1,0,0,0,0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "26") (term "0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "26") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "26") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "26") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "26") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "commute_or_2" (formula "26") (term "0")) + (rule "allLeft" (formula "20") (inst "t=Z(0(#)):int")) + (rule "leq_literals" (formula "20") (term "1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "applyEq" (formula "20") (term "0,0,0") (ifseqformula "34")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "37")) + (rule "qeq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "replace_known_right" (formula "32") (term "0") (ifseqformula "38")) + (builtin "One Step Simplification" (formula "32")) + (rule "allLeft" (formula "20") (inst "t=nv_0:int")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "24") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "eqSymm" (formula "24") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "24") (term "0,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,0,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,0,0")) + (rule "add_literals" (formula "24") (term "0,0,0,0")) + (rule "add_zero_left" (formula "24") (term "0,0,0")) + (rule "inEqSimp_homoInEq1" (formula "24") (term "1,0")) + (rule "polySimp_mulComm0" (formula "24") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "24") (term "1,0,1,0")) + (rule "mul_literals" (formula "24") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "24") (term "0,1,0")) + (rule "polySimp_addComm0" (formula "24") (term "0,0,1,0")) + (rule "polySimp_pullOutFactor1b" (formula "24") (term "0,1,0")) + (rule "add_literals" (formula "24") (term "1,1,0,1,0")) + (rule "times_zero_1" (formula "24") (term "1,0,1,0")) + (rule "add_literals" (formula "24") (term "0,1,0")) + (rule "leq_literals" (formula "24") (term "1,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "applyEq" (formula "24") (term "1,1,1") (ifseqformula "35")) + (rule "inEqSimp_invertInEq1" (formula "24") (term "0")) + (rule "polySimp_mulLiterals" (formula "24") (term "0,0")) + (rule "mul_literals" (formula "24") (term "1,0")) + (rule "polySimp_elimOne" (formula "24") (term "0,0")) + (rule "inEqSimp_contradInEq1" (formula "24") (term "0") (ifseqformula "37")) + (rule "qeq_literals" (formula "24") (term "0,0")) + (builtin "One Step Simplification" (formula "24")) + (rule "allLeft" (formula "25") (inst "t=i_0_0:int")) + (rule "eqSymm" (formula "25") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "25") (term "1,0")) + (rule "applyEq" (formula "25") (term "1,1,1") (ifseqformula "13")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0,0") (ifseqformula "11")) + (rule "qeq_literals" (formula "25") (term "0,0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "inEqSimp_contradInEq1" (formula "25") (term "0") (ifseqformula "12")) + (rule "inEqSimp_homoInEq1" (formula "25") (term "0,0")) + (rule "polySimp_pullOutFactor1b" (formula "25") (term "0,0,0")) + (rule "add_literals" (formula "25") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "25") (term "1,0,0,0")) + (rule "add_literals" (formula "25") (term "0,0,0")) + (rule "leq_literals" (formula "25") (term "0,0")) + (builtin "One Step Simplification" (formula "25")) + (rule "allLeft" (formula "20") (inst "t=add(Z(neglit(1(#))), + select<[int]>(heap, self, LinkedList::#size)):int")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "add_zero_left" (formula "20") (term "0,1,0")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1")) + (rule "polySimp_addComm0" (formula "20") (term "0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,1")) + (rule "add_literals" (formula "20") (term "0,1")) + (rule "leq_literals" (formula "20") (term "1")) + (builtin "One Step Simplification" (formula "20")) + (rule "applyEq" (formula "20") (term "0,0,0") (ifseqformula "37")) + (rule "inEqSimp_invertInEq1" (formula "20") (term "1")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1")) + (rule "mul_literals" (formula "20") (term "1,1")) + (rule "polySimp_elimOne" (formula "20") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "39")) + (rule "qeq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "26") (inst "t=add(Z(1(#)), i_0):int")) + (rule "eqSymm" (formula "26") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "26") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "26") (term "0,0")) + (rule "polySimp_mulComm0" (formula "26") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "26") (term "1,0,0,0")) + (rule "mul_literals" (formula "26") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "26") (term "0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "26") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "26") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "26") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "0,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "26") (term "0,0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "inEqSimp_contradInEq1" (formula "26") (term "0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "26") (term "0,0")) + (rule "polySimp_mulComm0" (formula "26") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "26") (term "1,0,0,0")) + (rule "mul_literals" (formula "26") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "26") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "26") (term "0,0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "26") (term "0,0,0")) + (rule "add_literals" (formula "26") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "26") (term "1,0,0,0")) + (rule "add_literals" (formula "26") (term "0,0,0")) + (rule "leq_literals" (formula "26") (term "0,0")) + (builtin "One Step Simplification" (formula "26")) + (rule "allLeft" (formula "27") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "eqSymm" (formula "27") (term "1")) + (rule "inEqSimp_commuteGeq" (formula "27") (term "1,0")) + (rule "inEqSimp_homoInEq0" (formula "27") (term "0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "27") (term "0,0")) + (rule "polySimp_mulLiterals" (formula "27") (term "0,0,0")) + (rule "polySimp_elimOne" (formula "27") (term "0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "27") (term "0,0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "inEqSimp_contradInEq1" (formula "27") (term "0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "27") (term "0,0")) + (rule "polySimp_mulComm0" (formula "27") (term "1,0,0,0")) + (rule "polySimp_rightDist" (formula "27") (term "1,0,0,0")) + (rule "mul_literals" (formula "27") (term "0,1,0,0,0")) + (rule "polySimp_addAssoc" (formula "27") (term "0,0,0")) + (rule "polySimp_addComm1" (formula "27") (term "0,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "27") (term "0,0,0")) + (rule "add_literals" (formula "27") (term "1,1,0,0,0")) + (rule "times_zero_1" (formula "27") (term "1,0,0,0")) + (rule "add_literals" (formula "27") (term "0,0,0")) + (rule "leq_literals" (formula "27") (term "0,0")) + (builtin "One Step Simplification" (formula "27")) + (rule "allLeft" (formula "31") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "31") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "31") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "31") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "31") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "inEqSimp_contradInEq1" (formula "31") (term "1,0,0,0,0") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "31") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "31") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "31") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "31") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "31") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "31") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "31")) + (rule "allLeft" (formula "32") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_commuteGeq" (formula "32") (term "1,0,0,0,0")) + (rule "inEqSimp_homoInEq0" (formula "32") (term "1,0,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "32") (term "1,0,1,0,0,0,0,0")) + (rule "polySimp_rightDist" (formula "32") (term "1,0,1,0,0,0,0,0")) + (rule "mul_literals" (formula "32") (term "0,1,0,1,0,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "32") (term "0,1,0,0,0,0,0")) + (rule "add_literals" (formula "32") (term "0,0,1,0,0,0,0,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "32") (term "1,0,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "32") (term "0,1,0,0,0,0,0")) + (rule "polySimp_elimOne" (formula "32") (term "0,1,0,0,0,0,0")) + (rule "inEqSimp_contradInEq1" (formula "32") (term "1,0,0,0,0,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "32") (term "0,1,0,0,0,0,0")) + (builtin "One Step Simplification" (formula "32")) + (rule "inEqSimp_contradInEq1" (formula "32") (term "1,0,0,0,0") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "32") (term "0,1,0,0,0,0")) + (rule "polySimp_mulComm0" (formula "32") (term "1,0,0,1,0,0,0,0")) + (rule "polySimp_rightDist" (formula "32") (term "1,0,0,1,0,0,0,0")) + (rule "mul_literals" (formula "32") (term "0,1,0,0,1,0,0,0,0")) + (rule "polySimp_addAssoc" (formula "32") (term "0,0,1,0,0,0,0")) + (rule "polySimp_addComm1" (formula "32") (term "0,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "32") (term "0,0,0,0,1,0,0,0,0")) + (rule "polySimp_pullOutFactor1b" (formula "32") (term "0,0,1,0,0,0,0")) + (rule "add_literals" (formula "32") (term "1,1,0,0,1,0,0,0,0")) + (rule "times_zero_1" (formula "32") (term "1,0,0,1,0,0,0,0")) + (rule "add_literals" (formula "32") (term "0,0,1,0,0,0,0")) + (rule "leq_literals" (formula "32") (term "0,1,0,0,0,0")) + (builtin "One Step Simplification" (formula "32")) + (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), i_0):int")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "20") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "4")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "allLeft" (formula "20") (inst "t=add(Z(1(#)), nv_0):int")) + (rule "inEqSimp_commuteGeq" (formula "20") (term "1")) + (rule "inEqSimp_homoInEq0" (formula "20") (term "1,0")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,1,0")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,1,0")) + (rule "mul_literals" (formula "20") (term "0,1,0,1,0")) + (rule "polySimp_addAssoc" (formula "20") (term "0,1,0")) + (rule "add_literals" (formula "20") (term "0,0,1,0")) + (rule "inEqSimp_sepNegMonomial1" (formula "20") (term "1,0")) + (rule "polySimp_mulLiterals" (formula "20") (term "0,1,0")) + (rule "polySimp_elimOne" (formula "20") (term "0,1,0")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1,0") (ifseqformula "7")) + (rule "qeq_literals" (formula "20") (term "0,1,0")) + (builtin "One Step Simplification" (formula "20")) + (rule "inEqSimp_contradInEq1" (formula "20") (term "1") (ifseqformula "6")) + (rule "inEqSimp_homoInEq1" (formula "20") (term "0,1")) + (rule "polySimp_mulComm0" (formula "20") (term "1,0,0,1")) + (rule "polySimp_rightDist" (formula "20") (term "1,0,0,1")) + (rule "mul_literals" (formula "20") (term "0,1,0,0,1")) + (rule "polySimp_addAssoc" (formula "20") (term "0,0,1")) + (rule "polySimp_addComm1" (formula "20") (term "0,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,0,0,1")) + (rule "polySimp_pullOutFactor1b" (formula "20") (term "0,0,1")) + (rule "add_literals" (formula "20") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "20") (term "1,0,0,1")) + (rule "add_literals" (formula "20") (term "0,0,1")) + (rule "leq_literals" (formula "20") (term "0,1")) + (builtin "One Step Simplification" (formula "20")) + (rule "notLeft" (formula "20")) + (rule "referencedObjectIsCreatedRightEQ" (formula "51") (ifseqformula "36") (ifseqformula "44")) + (rule "close" (formula "51") (ifseqformula "15")) ) ) ) @@ -2520,7 +3974,7 @@ (rule "mul_literals" (formula "13") (term "1,0,0,0,1,0,1,0")) (rule "nnf_imp2or" (formula "13") (term "1,0,1,0,1,0")) (rule "commute_or" (formula "3") (term "1")) - (rule "Class_invariant_axiom_for_LinkedList" (formula "21") (inst "i=i") (inst "j=j") (inst "i_0=i_0") (ifseqformula "20")) + (rule "Class_invariant_axiom_for_LinkedList" (formula "21") (inst "i=i") (inst "i_0=i_0") (inst "j=j") (ifseqformula "20")) (builtin "One Step Simplification" (formula "21")) (rule "eqSymm" (formula "21") (term "1,0,0,1,0,1,0,0,0")) (rule "eqSymm" (formula "21") (term "0,1")) @@ -2538,215 +3992,132 @@ (rule "polySimp_addComm0" (formula "21") (term "1,0,2,0,1,1,0,1,0,0,0")) (rule "polySimp_addComm0" (formula "21") (term "1,0,0,1,1,0,1,0,0,0")) (rule "polySimp_addComm0" (formula "21") (term "1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "subsetSingletonLeft" (formula "21") (term "0,0,0,0,0,0")) + (rule "subsetSingletonLeft" (formula "21") (term "1,0,0,0,0,0")) + (rule "castedGetAny" (formula "21") (term "0,1,0,1,0,1,0,0,0,0")) (rule "castedGetAny" (formula "21") (term "0,0,0,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,1,1,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,0,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,1,1")) - (rule "eqSymm" (formula "21") (term "1,1")) - (rule "castedGetAny" (formula "21") (term "2,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0")) - (rule "castedGetAny" (formula "21") (term "1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,2,0,1,1,0,1,0,0,0")) - (rule "castedGetAny" (formula "21") (term "1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,0,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,0,0,0,0,0,0")) - (rule "castedGetAny" (formula "21") (term "1,1,1,0,0,1,0,1,0,0,0")) (rule "castedGetAny" (formula "21") (term "0,1,0,0,1,0,1,0,0,0")) (rule "eqSymm" (formula "21") (term "1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,0,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,1")) - (rule "eqSymm" (formula "21") (term "1,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,2,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,1,0,1,0,0,0")) - (rule "castedGetAny" (formula "21") (term "2,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "castedGetAny" (formula "21") (term "0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,0,0,0,1,0,1,0,0,0")) - (rule "subsetSingletonLeft" (formula "21") (term "1,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,0,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,0,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,0,0")) - (rule "castedGetAny" (formula "21") (term "0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,1,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,2,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,0")) - (rule "inEqSimp_commuteLeq" (formula "21") (term "0,0,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_commuteLeq" (formula "21") (term "0,0,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,2,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_commuteLeq" (formula "21") (term "0,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,0,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,0,2,0,1,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,0,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "2,1,0,0,0,0,0")) - (rule "subsetSingletonLeft" (formula "21") (term "0,0,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,0,1,0,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,1,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,1,1")) - (rule "dismissNonSelectedField" (formula "21") (term "0,2,0,1,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,2,0,1,1,0,1,0,0,0")) - (rule "inEqSimp_ltToLeq" (formula "21") (term "1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1,0,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,0,1,0,1,0,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,0,0,1,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_ltToLeq" (formula "21") (term "1,0,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1,0,0,1,0,0,0")) + (rule "castedGetAny" (formula "21") (term "0,0,1,0,1,0,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "21") (term "1,0,1,0,1,0,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "21") (term "2,0,1,1,0,1,0,0,0")) + (rule "eqSymm" (formula "21") (term "1,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "21") (term "2,0,1,0,0")) (rule "castedGetAny" (formula "21") (term "2,0,1,0")) + (rule "castedGetAny" (formula "21") (term "1,0,1,0,0,1,0,1,0,0,0")) + (rule "castedGetAny" (formula "21") (term "1,0,1,1,0,1,0,0,0")) + (rule "eqSymm" (formula "21") (term "1,1,0,1,0,0,0")) (rule "inEqSimp_ltToLeq" (formula "21") (term "1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1,0,0,1,0,1,0,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "0,1,1,1,1,0,1,0,0,0")) - (rule "dismissNonSelectedField" (formula "21") (term "1,1,1,0,1,0,0,0")) - (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_rightDist" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "mul_literals" (formula "21") (term "0,1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "polySimp_elimOne" (formula "21") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) - (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1,0,0,1,0,0,0")) - (rule "polySimp_mulComm0" (formula "21") (term "1,1,0,0,1,0,0,0")) - (rule "polySimp_rightDist" (formula "21") (term "1,1,0,0,1,0,0,0")) - (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1,0,0,1,0,0,0")) - (rule "mul_literals" (formula "21") (term "0,1,1,0,0,1,0,0,0")) - (rule "polySimp_elimOne" (formula "21") (term "1,1,1,0,0,1,0,0,0")) + (rule "inEqSimp_ltToLeq" (formula "21") (term "1,0,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1,0,0,1,0,0,0")) + (rule "inEqSimp_ltToLeq" (formula "21") (term "1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "21") (term "1,0,0,1,0,0,1,0,1,0,1,0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "21") (term "0,0,0,1,0,1,0,0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "21") (term "0,0,0,1,0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "21") (term "0,0,0,1,0,1,0,1,0,0,0")) (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_mulComm0" (formula "21") (term "1,1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_rightDist" (formula "21") (term "1,1,0,0,1,0,1,0,0,0,0")) - (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1,0,0,1,0,1,0,0,0,0")) (rule "mul_literals" (formula "21") (term "0,1,1,0,0,1,0,1,0,0,0,0")) + (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1,0,0,1,0,1,0,0,0,0")) (rule "polySimp_elimOne" (formula "21") (term "1,1,1,0,0,1,0,1,0,0,0,0")) - (rule "pullOutSelect" (formula "21") (term "1,0,1") (inst "selectSK=LinkedList_size_0")) - (rule "applyEq" (formula "22") (term "1,1,2,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,0,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "1,1,1,0,0,1,0,1,0,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1,0,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "21") (term "1,1,0,0,1,0,0,0")) + (rule "polySimp_rightDist" (formula "21") (term "1,1,0,0,1,0,0,0")) + (rule "mul_literals" (formula "21") (term "0,1,1,0,0,1,0,0,0")) + (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1,0,0,1,0,0,0")) + (rule "polySimp_elimOne" (formula "21") (term "1,1,1,0,0,1,0,0,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "21") (term "1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_mulComm0" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_rightDist" (formula "21") (term "1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "mul_literals" (formula "21") (term "0,1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_mulLiterals" (formula "21") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "polySimp_elimOne" (formula "21") (term "1,1,1,0,0,1,0,1,0,1,0,0,0")) + (rule "pullOutSelect" (formula "21") (term "1,1,0,0,0,0") (inst "selectSK=List_footprint_0:LocSet")) + (rule "applyEq" (formula "22") (term "2,0,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "2,1,0,0,0,0,0") (ifseqformula "1")) + (rule "simplifySelectOfCreate" (formula "1")) + (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) + (rule "applyEqReverse" (formula "22") (term "2,0,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "2,1,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "1,1,0,0,0,0") (ifseqformula "1")) + (rule "hideAuxiliaryEq" (formula "1")) + (rule "elementOfUnionEQ" (formula "21") (term "0,0,0,0,0,0") (ifseqformula "12")) + (builtin "One Step Simplification" (formula "21")) + (rule "elementOfUnionEQ" (formula "21") (term "0,0,0,0,0") (ifseqformula "12")) + (builtin "One Step Simplification" (formula "21")) + (rule "pullOutSelect" (formula "21") (term "1,1,1,0,0,1,0,0,0,0,0") (inst "selectSK=LinkedList_size_0:int")) (rule "applyEq" (formula "22") (term "1,1,1,0,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "0,0,0,1,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "0,0,0,1,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "1,1,2,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "1,1,0,0,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "1,0,1") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "1,1,1") (ifseqformula "1")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) - (rule "applyEqReverse" (formula "22") (term "1,0,1") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "1,1,2,0,1,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,0,0,1,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "1,1,1,0,0,1,0,1,0,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "1,1,1,0,0,1,0,0,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "1,1,1,0,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,0,0,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "1,1,1,0,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "1,1,0,0,1,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,0,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,0,1,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "1,1,2,0,1,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "1,0,1") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "1,1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "pullOutSelect" (formula "21") (term "0,0,0,1") (inst "selectSK=List_seq_0")) - (rule "applyEq" (formula "22") (term "0,1,1,0,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "simplifySelectOfCreate" (formula "1")) - (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) - (rule "applyEqReverse" (formula "22") (term "0,0,0,1") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,1,1,0,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "hideAuxiliaryEq" (formula "1")) - (rule "replace_known_left" (formula "21") (term "0,1") (ifseqformula "16")) - (builtin "One Step Simplification" (formula "21")) - (rule "pullOutSelect" (formula "21") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (inst "selectSK=LinkedList_nodeseq_0")) + (rule "pullOutSelect" (formula "21") (term "0,0,1,0,1,0,0,0,0,0") (inst "selectSK=LinkedList_nodeseq_0:Seq")) + (rule "applyEq" (formula "22") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "0,1,0,1,0,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,2,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,2,0,1,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,0,1,0,1,0,1,0,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "0,1,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "0,2,0,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,0,1") (ifseqformula "1")) (rule "applyEq" (formula "22") (term "0,1,1,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "0,2,0,1,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "0,2,0,1,0") (ifseqformula "1")) + (rule "applyEq" (formula "22") (term "0,0,1,1") (ifseqformula "1")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) - (rule "applyEqReverse" (formula "22") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,1,0,1,0,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "0,1,0,1,0,0,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,2,0,1,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,2,0,1,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,0,1,0,1,0,1,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "0,1,0,1,0,1,0,1,0,1,0,0,0") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "0,2,0,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,0,1") (ifseqformula "1")) (rule "applyEqReverse" (formula "22") (term "0,1,1,1,1,0,1,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,0,0,0,0,0,1,0,1,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,2,0,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,2,0,1,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "replace_known_left" (formula "21") (term "1") (ifseqformula "17")) - (builtin "One Step Simplification" (formula "21")) - (rule "applyEq" (formula "21") (term "0,1,0") (ifseqformula "14")) + (rule "replace_known_left" (formula "21") (term "0,0,0,0") (ifseqformula "12")) + (builtin "One Step Simplification" (formula "21") (ifInst "" (formula "17"))) + (rule "applyEq" (formula "21") (term "0,1,0,0") (ifseqformula "14")) + (rule "eqSymm" (formula "21") (term "1,0,0")) + (rule "applyEq" (formula "21") (term "0,1,0") (ifseqformula "15")) (rule "eqSymm" (formula "21") (term "1,0")) - (rule "applyEq" (formula "21") (term "0,1,0,0,0") (ifseqformula "12")) - (rule "eqSymm" (formula "21") (term "1,0,0,0")) - (rule "applyEq" (formula "21") (term "0,1") (ifseqformula "15")) - (rule "eqSymm" (formula "21") (term "1")) - (rule "pullOutSelect" (formula "21") (term "2,0,0,0,0,0") (inst "selectSK=List_footprint_0")) - (rule "applyEq" (formula "22") (term "2,1,0,0,0,0") (ifseqformula "1")) - (rule "applyEq" (formula "22") (term "0,1,0,0,0") (ifseqformula "1")) + (rule "pullOutSelect" (formula "21") (term "0,1,1,0,0,1,0,0,0,0") (inst "selectSK=List_seq_0:Seq")) + (rule "applyEq" (formula "22") (term "0,0,1") (ifseqformula "1")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) - (rule "applyEqReverse" (formula "22") (term "2,0,0,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "2,1,0,0,0,0") (ifseqformula "1")) - (rule "applyEqReverse" (formula "22") (term "0,1,0,0,0") (ifseqformula "1")) - (builtin "One Step Simplification" (formula "22")) + (rule "applyEqReverse" (formula "22") (term "0,1,1,0,0,1,0,0,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "22") (term "0,0,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "elementOfUnionEQ" (formula "21") (term "0,0,0,0") (ifseqformula "12")) - (builtin "One Step Simplification" (formula "21")) - (rule "elementOfUnionEQ" (formula "21") (term "0,0,0") (ifseqformula "12")) + (rule "replace_known_left" (formula "21") (term "1") (ifseqformula "16")) (builtin "One Step Simplification" (formula "21")) - (rule "pullOutSelect" (formula "21") (term "0,1,0") (inst "selectSK=LinkedList_first_0")) + (rule "pullOutSelect" (formula "21") (term "0,1,0") (inst "selectSK=LinkedList_first_0:Node")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) (rule "applyEqReverse" (formula "22") (term "0,1,0") (ifseqformula "1")) (builtin "One Step Simplification" (formula "22")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "pullOutSelect" (formula "21") (term "0,1") (inst "selectSK=LinkedList_last_0")) + (rule "pullOutSelect" (formula "21") (term "0,1") (inst "selectSK=LinkedList_last_0:Node")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "20"))) (rule "applyEqReverse" (formula "22") (term "0,1") (ifseqformula "1")) (builtin "One Step Simplification" (formula "22")) - (rule "allRight" (formula "22") (inst "sk=i_0")) + (rule "allRight" (formula "22") (inst "sk=i_0:int")) (rule "impRight" (formula "22")) (rule "andLeft" (formula "1")) (rule "hideAuxiliaryEq" (formula "3")) @@ -2766,34 +4137,34 @@ (rule "mul_literals" (formula "2") (term "0,1")) (rule "polySimp_mulLiterals" (formula "2") (term "1,1")) (rule "polySimp_elimOne" (formula "2") (term "1,1")) - (rule "pullOutSelect" (formula "23") (term "1,1") (inst "selectSK=Node_next_0")) + (rule "pullOutSelect" (formula "23") (term "0,1,0,0") (inst "selectSK=Node_data_0:int")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) + (rule "eqSymm" (formula "24") (term "1,0,0")) (rule "eqSymm" (formula "1") (term "0,0")) - (rule "pullOutSelect" (formula "24") (term "0,1,0,0") (inst "selectSK=Node_data_0")) + (rule "pullOutSelect" (formula "24") (term "1,1") (inst "selectSK=Node_next_0:Node")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) - (rule "eqSymm" (formula "25") (term "1,0,0")) (rule "eqSymm" (formula "1") (term "0,0")) - (rule "dismissNonSelectedField" (formula "1") (term "2,0")) - (rule "dismissNonSelectedField" (formula "1") (term "2,0")) - (rule "pullOutSelect" (formula "2") (term "2,0") (inst "selectSK=Node_next_1")) + (rule "pullOutSelect" (formula "2") (term "2,0") (inst "selectSK=Node_data_1:int")) (rule "simplifySelectOfCreate" (formula "2")) (builtin "One Step Simplification" (formula "2") (ifInst "" (formula "24"))) (rule "applyEqReverse" (formula "3") (term "2,0") (ifseqformula "2")) (rule "hideAuxiliaryEq" (formula "2")) - (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=Node_data_1")) + (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=Node_next_1:Node")) (rule "simplifySelectOfCreate" (formula "1")) (builtin "One Step Simplification" (formula "1") (ifInst "" (formula "24"))) (rule "applyEqReverse" (formula "2") (term "2,0") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "shift_paren_or" (formula "5") (term "0")) (rule "nnf_imp2or" (formula "25") (term "0,1,0")) - (rule "shift_paren_or" (formula "7")) - (rule "nnf_imp2or" (formula "25") (term "1,0,1,0")) (rule "nnf_notAnd" (formula "25") (term "0,0,1,0")) + (rule "inEqSimp_notGeq" (formula "25") (term "0,0,0,1,0")) + (rule "mul_literals" (formula "25") (term "1,0,0,0,0,0,1,0")) + (rule "add_literals" (formula "25") (term "0,0,0,0,0,1,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "25") (term "0,0,0,1,0")) + (rule "mul_literals" (formula "25") (term "1,0,0,0,1,0")) (rule "inEqSimp_notLeq" (formula "25") (term "1,0,0,1,0")) (rule "polySimp_rightDist" (formula "25") (term "1,0,0,1,0,0,1,0")) (rule "mul_literals" (formula "25") (term "0,1,0,0,1,0,0,1,0")) @@ -2803,39 +4174,39 @@ (rule "inEqSimp_sepPosMonomial1" (formula "25") (term "1,0,0,1,0")) (rule "polySimp_mulLiterals" (formula "25") (term "1,1,0,0,1,0")) (rule "polySimp_elimOne" (formula "25") (term "1,1,0,0,1,0")) - (rule "inEqSimp_notGeq" (formula "25") (term "0,0,0,1,0")) - (rule "mul_literals" (formula "25") (term "1,0,0,0,0,0,1,0")) - (rule "add_literals" (formula "25") (term "0,0,0,0,0,1,0")) - (rule "inEqSimp_sepPosMonomial0" (formula "25") (term "0,0,0,1,0")) - (rule "mul_literals" (formula "25") (term "1,0,0,0,1,0")) + (rule "nnf_imp2or" (formula "25") (term "1,0,1,0")) + (rule "shift_paren_or" (formula "7")) + (rule "shift_paren_or" (formula "5") (term "0")) + (rule "shift_paren_or" (formula "17") (term "0,1,0,1,0")) (rule "ifthenelse_to_or_left" (formula "17") (term "1,1,0")) (rule "eqSymm" (formula "17") (term "1,0,1,1,0")) (rule "eqSymm" (formula "17") (term "1,1,1,1,0")) - (rule "shift_paren_or" (formula "17") (term "0,1,0,1,0")) + (rule "commute_or_2" (formula "5") (term "0")) + (rule "commute_or" (formula "5") (term "0,0")) (rule "ifthenelse_split" (formula "18") (term "0")) (branch "self.size = 0 TRUE" (rule "eqSymm" (formula "19")) (rule "replace_known_left" (formula "20") (term "0,0") (ifseqformula "18")) (builtin "One Step Simplification" (formula "20")) (rule "eqSymm" (formula "20")) - (rule "applyEq" (formula "17") (term "1,1,0,0") (ifseqformula "18")) - (rule "applyEq" (formula "9") (term "0") (ifseqformula "18")) - (rule "inEqSimp_homoInEq1" (formula "9")) - (rule "mul_literals" (formula "9") (term "1,0")) - (rule "add_zero_right" (formula "9") (term "0")) - (rule "applyEq" (formula "16") (term "1,1,1,0,0,1,0") (ifseqformula "18")) - (rule "add_literals" (formula "16") (term "1,1,0,0,1,0")) + (rule "applyEq" (formula "26") (term "1,1,0,0,1,0") (ifseqformula "18")) (rule "applyEq" (formula "26") (term "0,0,0,1") (ifseqformula "18")) (rule "polySimp_homoEq" (formula "26") (term "0,0,1")) (rule "mul_literals" (formula "26") (term "1,0,0,0,1")) (rule "add_zero_right" (formula "26") (term "0,0,0,1")) - (rule "applyEq" (formula "26") (term "1,1,0,0,1,0") (ifseqformula "18")) + (rule "applyEq" (formula "9") (term "0") (ifseqformula "18")) + (rule "inEqSimp_homoInEq1" (formula "9")) + (rule "mul_literals" (formula "9") (term "1,0")) + (rule "add_zero_right" (formula "9") (term "0")) (rule "applyEq" (formula "4") (term "0") (ifseqformula "18")) (rule "inEqSimp_homoInEq1" (formula "4")) - (rule "times_zero_2" (formula "4") (term "1,0")) + (rule "mul_literals" (formula "4") (term "1,0")) (rule "add_zero_right" (formula "4") (term "0")) - (rule "applyEq" (formula "5") (term "1,1,0,0") (ifseqformula "18")) + (rule "applyEq" (formula "17") (term "1,1,0,0") (ifseqformula "18")) + (rule "applyEq" (formula "16") (term "1,1,1,0,0,1,0") (ifseqformula "18")) + (rule "add_literals" (formula "16") (term "1,1,0,0,1,0")) (rule "applyEq" (formula "17") (term "1,1,0,0,0,1,0,1,0") (ifseqformula "18")) + (rule "applyEq" (formula "5") (term "1,1,0") (ifseqformula "18")) (rule "applyEq" (formula "17") (term "1,1,0,0,0,1,1,0") (ifseqformula "18")) (rule "add_literals" (formula "17") (term "1,0,0,0,1,1,0")) (rule "applyEq" (formula "17") (term "1,1,0,1,1,1,0") (ifseqformula "18")) @@ -2853,64 +4224,44 @@ (rule "mul_literals" (formula "26") (term "0,0,0,0,1")) (rule "leq_literals" (formula "26") (term "0,0,0,1")) (builtin "One Step Simplification" (formula "26")) - (rule "inEqSimp_contradInEq0" (formula "8") (ifseqformula "9")) - (rule "qeq_literals" (formula "8") (term "0")) - (builtin "One Step Simplification" (formula "8")) - (rule "closeFalse" (formula "8")) + (rule "inEqSimp_contradInEq0" (formula "3") (ifseqformula "4")) + (rule "qeq_literals" (formula "3") (term "0")) + (builtin "One Step Simplification" (formula "3")) + (rule "closeFalse" (formula "3")) ) (branch "self.size = 0 FALSE" (rule "replace_known_right" (formula "19") (term "0,0") (ifseqformula "22")) (builtin "One Step Simplification" (formula "19")) - (rule "lenNonNegative" (formula "20") (term "0")) - (rule "inEqSimp_commuteLeq" (formula "20")) - (rule "applyEq" (formula "20") (term "0") (ifseqformula "21")) - (rule "inEqSimp_strengthen1" (formula "20") (ifseqformula "23")) - (rule "add_literals" (formula "20") (term "1")) - (rule "inEqSimp_contradEq7" (formula "23") (ifseqformula "20")) + (rule "commute_or" (formula "17") (term "0,1,1,0")) + (rule "commute_or" (formula "17") (term "1,1,1,0")) + (rule "commute_or_2" (formula "17") (term "0,0,1,0,1,0")) + (rule "commute_or" (formula "17") (term "0,0,0,1,0,1,0")) + (rule "seqGetAlphaCast" (formula "10") (term "0")) + (rule "castedGetAny" (formula "10") (term "0")) + (builtin "One Step Simplification" (formula "10")) + (rule "true_left" (formula "10")) + (rule "lenNonNegative" (formula "21") (term "0")) + (rule "inEqSimp_commuteLeq" (formula "21")) + (rule "applyEq" (formula "21") (term "0") (ifseqformula "22")) + (rule "inEqSimp_strengthen1" (formula "21") (ifseqformula "23")) + (rule "add_literals" (formula "21") (term "1")) + (rule "inEqSimp_contradEq7" (formula "23") (ifseqformula "21")) (rule "mul_literals" (formula "23") (term "1,0,0")) (rule "add_literals" (formula "23") (term "0,0")) (rule "leq_literals" (formula "23") (term "0")) (builtin "One Step Simplification" (formula "23")) (rule "false_right" (formula "23")) - (rule "lenNonNegative" (formula "22") (term "0")) - (rule "inEqSimp_commuteLeq" (formula "22")) - (rule "applyEq" (formula "22") (term "0") (ifseqformula "23")) - (rule "inEqSimp_subsumption1" (formula "22") (ifseqformula "20")) - (rule "leq_literals" (formula "22") (term "0")) - (builtin "One Step Simplification" (formula "22")) - (rule "true_left" (formula "22")) - (rule "seqGetAlphaCast" (formula "10") (term "0")) - (rule "castedGetAny" (formula "10") (term "0")) - (builtin "One Step Simplification" (formula "10")) - (rule "true_left" (formula "10")) - (rule "commute_or_2" (formula "5") (term "0")) - (rule "commute_or" (formula "5") (term "0,0")) - (rule "commute_or" (formula "17") (term "0,1,1,0")) - (rule "commute_or" (formula "17") (term "1,1,1,0")) - (rule "commute_or_2" (formula "17") (term "0,0,1,0,1,0")) - (rule "commute_or" (formula "17") (term "0,0,0,1,0,1,0")) + (rule "lenNonNegative" (formula "20") (term "0")) + (rule "inEqSimp_commuteLeq" (formula "20")) + (rule "applyEq" (formula "20") (term "0") (ifseqformula "21")) + (rule "inEqSimp_subsumption1" (formula "20") (ifseqformula "22")) + (rule "leq_literals" (formula "20") (term "0")) + (builtin "One Step Simplification" (formula "20")) + (rule "true_left" (formula "20")) (rule "ifthenelse_split" (formula "26") (term "0,1")) (branch "self.size = 1 + i_0 TRUE" (rule "eqSymm" (formula "27") (term "1")) - (rule "applyEq" (formula "21") (term "0") (ifseqformula "1")) - (rule "inEqSimp_homoInEq1" (formula "21")) - (rule "polySimp_mulComm0" (formula "21") (term "1,0")) - (rule "polySimp_rightDist" (formula "21") (term "1,0")) - (rule "mul_literals" (formula "21") (term "0,1,0")) - (rule "polySimp_addAssoc" (formula "21") (term "0")) - (rule "add_literals" (formula "21") (term "0,0")) - (rule "add_zero_left" (formula "21") (term "0")) - (rule "applyEq" (formula "6") (term "1,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "17") (term "1,1,1,0,0,1,0") (ifseqformula "1")) - (rule "polySimp_addAssoc" (formula "17") (term "1,1,0,0,1,0")) - (rule "add_literals" (formula "17") (term "0,1,1,0,0,1,0")) - (rule "add_zero_left" (formula "17") (term "1,1,0,0,1,0")) - (rule "applyEq" (formula "18") (term "1,1,0,0,1,0,1,0") (ifseqformula "1")) - (rule "applyEq" (formula "20") (term "1,1,0") (ifseqformula "1")) - (rule "polySimp_addAssoc" (formula "20") (term "1,0")) - (rule "add_literals" (formula "20") (term "0,1,0")) - (rule "add_zero_left" (formula "20") (term "1,0")) - (rule "applyEq" (formula "18") (term "1,1,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "27") (term "1,1,0,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "10") (term "0") (ifseqformula "1")) (rule "inEqSimp_homoInEq1" (formula "10")) (rule "polySimp_mulComm0" (formula "10") (term "1,0")) @@ -2920,7 +4271,6 @@ (rule "polySimp_addAssoc" (formula "10") (term "0,0")) (rule "add_literals" (formula "10") (term "0,0,0")) (rule "add_zero_left" (formula "10") (term "0,0")) - (rule "applyEq" (formula "27") (term "1,1,0,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "5") (term "0") (ifseqformula "1")) (rule "inEqSimp_homoInEq1" (formula "5")) (rule "polySimp_pullOutFactor1" (formula "5") (term "0")) @@ -2928,12 +4278,25 @@ (rule "times_zero_1" (formula "5") (term "0")) (rule "leq_literals" (formula "5")) (rule "true_left" (formula "5")) - (rule "applyEq" (formula "26") (term "1,0,0,1,0,1,0") (ifseqformula "19")) - (rule "applyEq" (formula "2") (term "1,2,0") (ifseqformula "19")) - (rule "applyEq" (formula "26") (term "0,0,0,0,0") (ifseqformula "19")) - (rule "applyEq" (formula "3") (term "1,2,0") (ifseqformula "19")) - (rule "applyEq" (formula "2") (term "0,0,0") (ifseqformula "19")) - (rule "applyEq" (formula "3") (term "0,0,0") (ifseqformula "19")) + (rule "applyEq" (formula "21") (term "0") (ifseqformula "1")) + (rule "inEqSimp_homoInEq1" (formula "21")) + (rule "polySimp_mulComm0" (formula "21") (term "1,0")) + (rule "polySimp_rightDist" (formula "21") (term "1,0")) + (rule "mul_literals" (formula "21") (term "0,1,0")) + (rule "polySimp_addAssoc" (formula "21") (term "0")) + (rule "add_literals" (formula "21") (term "0,0")) + (rule "add_zero_left" (formula "21") (term "0")) + (rule "applyEq" (formula "17") (term "1,1,0,0") (ifseqformula "1")) + (rule "applyEq" (formula "16") (term "1,1,1,0,0,1,0") (ifseqformula "1")) + (rule "polySimp_addAssoc" (formula "16") (term "1,1,0,0,1,0")) + (rule "add_literals" (formula "16") (term "0,1,1,0,0,1,0")) + (rule "add_zero_left" (formula "16") (term "1,1,0,0,1,0")) + (rule "applyEq" (formula "17") (term "1,1,0,0,1,0,1,0") (ifseqformula "1")) + (rule "applyEq" (formula "5") (term "1,1,0") (ifseqformula "1")) + (rule "applyEq" (formula "19") (term "1,1,0") (ifseqformula "1")) + (rule "polySimp_addAssoc" (formula "19") (term "1,0")) + (rule "add_literals" (formula "19") (term "0,1,0")) + (rule "add_zero_left" (formula "19") (term "1,0")) (rule "applyEq" (formula "17") (term "1,1,0,1,0,1,1,0") (ifseqformula "1")) (rule "polySimp_addAssoc" (formula "17") (term "1,0,1,0,1,1,0")) (rule "add_literals" (formula "17") (term "0,1,0,1,0,1,1,0")) @@ -2943,14 +4306,20 @@ (rule "add_literals" (formula "17") (term "0,1,1,1,1,1,0")) (rule "add_zero_left" (formula "17") (term "1,1,1,1,1,0")) (rule "applyEq" (formula "22") (term "1") (ifseqformula "1")) - (rule "applyEq" (formula "21") (term "1") (ifseqformula "1")) - (rule "inEqSimp_invertInEq0" (formula "20")) - (rule "mul_literals" (formula "20") (term "1")) - (rule "polySimp_mulLiterals" (formula "20") (term "0")) - (rule "polySimp_elimOne" (formula "20") (term "0")) + (rule "applyEq" (formula "20") (term "1") (ifseqformula "1")) + (rule "applyEq" (formula "26") (term "0,0,0,0,0") (ifseqformula "19")) + (rule "applyEq" (formula "26") (term "1,0,0,1,0,1,0") (ifseqformula "19")) + (rule "applyEq" (formula "2") (term "0,0,0") (ifseqformula "19")) + (rule "applyEq" (formula "3") (term "0,0,0") (ifseqformula "19")) + (rule "applyEq" (formula "2") (term "1,2,0") (ifseqformula "19")) + (rule "applyEq" (formula "3") (term "1,2,0") (ifseqformula "19")) (rule "inEqSimp_sepPosMonomial0" (formula "9")) (rule "polySimp_mulLiterals" (formula "9") (term "1")) (rule "polySimp_elimOne" (formula "9") (term "1")) + (rule "inEqSimp_invertInEq0" (formula "21")) + (rule "polySimp_mulLiterals" (formula "21") (term "0")) + (rule "mul_literals" (formula "21") (term "1")) + (rule "polySimp_elimOne" (formula "21") (term "0")) (rule "inEqSimp_exactShadow3" (formula "8") (ifseqformula "9")) (rule "mul_literals" (formula "8") (term "0,0")) (rule "add_zero_left" (formula "8") (term "0")) @@ -2959,196 +4328,22 @@ (rule "castedGetAny" (formula "1") (term "0")) (builtin "One Step Simplification" (formula "1")) (rule "true_left" (formula "1")) - (rule "all_pull_out0" (formula "17") (term "1,0")) - (rule "shift_paren_and" (formula "17") (term "0,1,0")) - (rule "cut_direct" (formula "7") (term "1")) - (branch "CUT: fv_0 = java.lang.Object::#$initialized TRUE" - (builtin "One Step Simplification" (formula "8")) - (rule "true_left" (formula "8")) - (rule "all_pull_out3" (formula "17") (term "0")) - (rule "cnf_rightDist" (formula "17") (term "0,0")) - (rule "distr_forallAnd" (formula "17") (term "0")) - (builtin "One Step Simplification" (formula "17")) - (rule "distr_forallAnd" (formula "17")) - (rule "andLeft" (formula "17")) - (rule "shift_paren_or" (formula "18") (term "0")) - (rule "commute_or_2" (formula "18") (term "0,0")) - (rule "inEqSimp_or_weaken3" (formula "18") (term "0")) - (builtin "One Step Simplification" (formula "18")) - (rule "cnf_rightDist" (formula "17") (term "0,0")) - (rule "distr_forallAnd" (formula "17") (term "0")) - (builtin "One Step Simplification" (formula "17")) - (rule "distr_forallAnd" (formula "17")) - (rule "andLeft" (formula "17")) - (rule "commute_or_2" (formula "18") (term "0")) - (builtin "One Step Simplification" (formula "18")) - (rule "inEqSimp_homoInEq1" (formula "18") (term "1,1")) - (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,1,1")) - (rule "add_literals" (formula "18") (term "1,1,0,1,1")) - (rule "times_zero_1" (formula "18") (term "1,0,1,1")) - (rule "add_literals" (formula "18") (term "0,1,1")) - (rule "leq_literals" (formula "18") (term "1,1")) - (builtin "One Step Simplification" (formula "18")) - (rule "applyEq" (formula "18") (term "1,0,0") (ifseqformula "21")) - (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "18") (term "0,1")) - (builtin "One Step Simplification" (formula "18")) - (rule "applyEq" (formula "3") (term "2,0") (ifseqformula "18")) - (builtin "One Step Simplification" (formula "3")) - (rule "applyEqReverse" (formula "27") (term "0,1") (ifseqformula "3")) - (builtin "One Step Simplification" (formula "27")) - (rule "hideAuxiliaryEq" (formula "3")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "17") (term "0,0")) - (rule "commute_or_2" (formula "17") (term "0,0,0")) - (rule "cnf_rightDist" (formula "16") (term "0")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or" (formula "17") (term "0")) - (rule "commute_or_2" (formula "16") (term "0")) - (rule "commute_or" (formula "16") (term "0,0")) - (rule "commute_or_2" (formula "18") (term "0,0,0,0")) - (rule "shift_paren_or" (formula "18") (term "0,0,0,0,0")) - (rule "ifthenelse_split" (formula "2") (term "0")) - (branch "self.last = n_2 TRUE" - (rule "referencedObjectIsCreatedRightEQ" (formula "26") (ifseqformula "2") (ifseqformula "27")) - (rule "close" (formula "26") (ifseqformula "12")) - ) - (branch "self.last = n_2 FALSE" - (rule "applyEqReverse" (formula "29") (term "1,1,0") (ifseqformula "2")) - (rule "hideAuxiliaryEq" (formula "2")) - (rule "seqGetAlphaCast" (formula "20") (term "0")) - (rule "castedGetAny" (formula "20") (term "0")) - (builtin "One Step Simplification" (formula "20")) - (rule "true_left" (formula "20")) - (rule "onlyCreatedObjectsAreReferenced" (formula "20") (term "1") (ifseqformula "10")) - (rule "allLeft" (formula "3") (inst "t=i_0")) - (rule "inEqSimp_homoInEq1" (formula "3") (term "1")) - (rule "polySimp_pullOutFactor1b" (formula "3") (term "0,1")) - (rule "add_literals" (formula "3") (term "1,1,0,1")) - (rule "times_zero_1" (formula "3") (term "1,0,1")) - (rule "add_literals" (formula "3") (term "0,1")) - (rule "leq_literals" (formula "3") (term "1")) - (builtin "One Step Simplification" (formula "3")) - (rule "applyEq" (formula "3") (term "1,0,0") (ifseqformula "23")) - (rule "inEqSimp_contradInEq1" (formula "3") (term "1") (ifseqformula "2")) - (rule "qeq_literals" (formula "3") (term "0,1")) - (builtin "One Step Simplification" (formula "3")) - (rule "allLeft" (formula "4") (inst "t=i_0_0")) - (rule "applyEq" (formula "4") (term "1,0,0,0") (ifseqformula "10")) - (rule "replace_known_right" (formula "4") (term "0,0") (ifseqformula "28")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "0") (ifseqformula "8")) - (rule "qeq_literals" (formula "4") (term "0,0")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq0" (formula "4") (ifseqformula "9")) - (rule "andLeft" (formula "4")) - (rule "inEqSimp_homoInEq1" (formula "4")) - (rule "polySimp_pullOutFactor1b" (formula "4") (term "0")) - (rule "add_literals" (formula "4") (term "1,1,0")) - (rule "times_zero_1" (formula "4") (term "1,0")) - (rule "add_literals" (formula "4") (term "0")) - (rule "leq_literals" (formula "4")) - (rule "closeFalse" (formula "4")) - ) - ) - (branch "CUT: fv_0 = java.lang.Object::#$initialized FALSE" - (builtin "One Step Simplification" (formula "7")) - (rule "all_pull_out3" (formula "17") (term "0")) - (rule "cnf_rightDist" (formula "17") (term "0,0")) - (rule "distr_forallAnd" (formula "17") (term "0")) - (builtin "One Step Simplification" (formula "17")) - (rule "distr_forallAnd" (formula "17")) - (rule "andLeft" (formula "17")) - (rule "shift_paren_or" (formula "18") (term "0")) - (rule "commute_or_2" (formula "18") (term "0,0")) - (rule "inEqSimp_or_weaken3" (formula "18") (term "0")) - (builtin "One Step Simplification" (formula "18")) - (rule "cnf_rightDist" (formula "17") (term "0,0")) - (rule "distr_forallAnd" (formula "17") (term "0")) - (builtin "One Step Simplification" (formula "17")) - (rule "distr_forallAnd" (formula "17")) - (rule "andLeft" (formula "17")) - (rule "commute_or_2" (formula "18") (term "0")) - (builtin "One Step Simplification" (formula "18")) - (rule "inEqSimp_homoInEq1" (formula "18") (term "1,1")) - (rule "polySimp_pullOutFactor1b" (formula "18") (term "0,1,1")) - (rule "add_literals" (formula "18") (term "1,1,0,1,1")) - (rule "times_zero_1" (formula "18") (term "1,0,1,1")) - (rule "add_literals" (formula "18") (term "0,1,1")) - (rule "leq_literals" (formula "18") (term "1,1")) - (builtin "One Step Simplification" (formula "18")) - (rule "applyEq" (formula "18") (term "1,0,0") (ifseqformula "21")) - (rule "inEqSimp_contradInEq1" (formula "18") (term "1") (ifseqformula "4")) - (rule "qeq_literals" (formula "18") (term "0,1")) - (builtin "One Step Simplification" (formula "18")) - (rule "applyEq" (formula "3") (term "2,0") (ifseqformula "18")) - (builtin "One Step Simplification" (formula "3")) - (rule "applyEqReverse" (formula "28") (term "0,1") (ifseqformula "3")) - (builtin "One Step Simplification" (formula "28")) - (rule "hideAuxiliaryEq" (formula "3")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "17") (term "0,0")) - (rule "commute_or_2" (formula "17") (term "0,0,0")) - (rule "cnf_rightDist" (formula "16") (term "0")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "16") (term "0")) - (rule "commute_or" (formula "17") (term "0")) - (rule "commute_or" (formula "16") (term "0,0")) - (rule "commute_or_2" (formula "18") (term "0,0,0,0")) - (rule "shift_paren_or" (formula "18") (term "0,0,0,0,0")) - (rule "ifthenelse_split" (formula "2") (term "0")) - (branch "self.last = n_2 TRUE" - (rule "referencedObjectIsCreatedRightEQ" (formula "27") (ifseqformula "2") (ifseqformula "28")) - (rule "close" (formula "27") (ifseqformula "12")) - ) - (branch "self.last = n_2 FALSE" - (rule "applyEqReverse" (formula "30") (term "1,1,0") (ifseqformula "2")) - (rule "hideAuxiliaryEq" (formula "2")) - (rule "seqGetAlphaCast" (formula "20") (term "0")) - (rule "castedGetAny" (formula "20") (term "0")) - (builtin "One Step Simplification" (formula "20")) - (rule "true_left" (formula "20")) - (rule "onlyCreatedObjectsAreReferenced" (formula "20") (term "1") (ifseqformula "10")) - (rule "allLeft" (formula "3") (inst "t=i_0")) - (rule "inEqSimp_homoInEq1" (formula "3") (term "1")) - (rule "polySimp_pullOutFactor1b" (formula "3") (term "0,1")) - (rule "add_literals" (formula "3") (term "1,1,0,1")) - (rule "times_zero_1" (formula "3") (term "1,0,1")) - (rule "add_zero_right" (formula "3") (term "0,1")) - (rule "leq_literals" (formula "3") (term "1")) - (builtin "One Step Simplification" (formula "3")) - (rule "applyEq" (formula "3") (term "1,0,0") (ifseqformula "23")) - (rule "inEqSimp_contradInEq1" (formula "3") (term "1") (ifseqformula "2")) - (rule "qeq_literals" (formula "3") (term "0,1")) - (builtin "One Step Simplification" (formula "3")) - (rule "allLeft" (formula "4") (inst "t=i_0_0")) - (rule "applyEq" (formula "4") (term "1,0,0,0") (ifseqformula "10")) - (rule "replace_known_right" (formula "4") (term "0,0") (ifseqformula "29")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "0") (ifseqformula "8")) - (rule "qeq_literals" (formula "4") (term "0,0")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq1" (formula "9") (ifseqformula "4")) - (rule "andLeft" (formula "9")) - (rule "inEqSimp_homoInEq1" (formula "9")) - (rule "polySimp_pullOutFactor1b" (formula "9") (term "0")) - (rule "add_literals" (formula "9") (term "1,1,0")) - (rule "times_zero_1" (formula "9") (term "1,0")) - (rule "add_zero_right" (formula "9") (term "0")) - (rule "leq_literals" (formula "9")) - (rule "closeFalse" (formula "9")) - ) - ) + (rule "allLeft" (formula "5") (inst "t=i_0_0:int")) + (rule "applyEq" (formula "5") (term "1,0,0,0") (ifseqformula "11")) + (rule "replace_known_right" (formula "5") (term "0,0") (ifseqformula "23")) + (builtin "One Step Simplification" (formula "5")) + (rule "inEqSimp_contradInEq1" (formula "5") (term "0") (ifseqformula "9")) + (rule "qeq_literals" (formula "5") (term "0,0")) + (builtin "One Step Simplification" (formula "5")) + (rule "inEqSimp_contradInEq0" (formula "5") (ifseqformula "10")) + (rule "andLeft" (formula "5")) + (rule "inEqSimp_homoInEq1" (formula "5")) + (rule "polySimp_pullOutFactor1b" (formula "5") (term "0")) + (rule "add_literals" (formula "5") (term "1,1,0")) + (rule "times_zero_1" (formula "5") (term "1,0")) + (rule "add_literals" (formula "5") (term "0")) + (rule "leq_literals" (formula "5")) + (rule "closeFalse" (formula "5")) ) (branch "self.size = 1 + i_0 FALSE" (rule "inEqSimp_strengthen1" (formula "4") (ifseqformula "26")) @@ -3169,474 +4364,69 @@ (rule "false_right" (formula "26")) (rule "ifthenelse_split" (formula "2") (term "0")) (branch "(Node)self.nodeseq[i_0] = n_2 TRUE" - (rule "applyEqReverse" (formula "27") (term "1,1") (ifseqformula "3")) + (rule "applyEqReverse" (formula "27") (term "1,1,0,0") (ifseqformula "3")) (rule "hideAuxiliaryEq" (formula "3")) (rule "replace_known_left" (formula "1") (term "0,0") (ifseqformula "2")) (builtin "One Step Simplification" (formula "1")) - (rule "applyEqReverse" (formula "26") (term "1,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "26") (term "1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) - (rule "applyEq" (formula "25") (term "1,0,0,1,0,1,0") (ifseqformula "1")) (rule "applyEq" (formula "25") (term "0,0,0,0,0") (ifseqformula "1")) (rule "replace_known_right" (formula "25") (term "0,0,0,0") (ifseqformula "23")) (builtin "One Step Simplification" (formula "25")) + (rule "applyEq" (formula "25") (term "1,0,0,1,0,1,0") (ifseqformula "1")) (rule "all_pull_out1" (formula "16") (term "0,1,0")) - (rule "all_pull_out0" (formula "16") (term "1,0")) - (rule "shift_paren_and" (formula "16") (term "0,1,0")) - (rule "all_pull_out3" (formula "16") (term "0")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "shift_paren_or" (formula "17") (term "0")) - (rule "commute_or_2" (formula "17") (term "0,0")) - (rule "inEqSimp_or_weaken3" (formula "17") (term "0")) - (rule "polySimp_addAssoc" (formula "17") (term "1,0,1,0")) - (rule "add_literals" (formula "17") (term "0,1,0,1,0")) - (rule "add_zero_left" (formula "17") (term "1,0,1,0")) - (builtin "One Step Simplification" (formula "17")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "17") (term "0")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "1,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,1")) - (rule "polySimp_addComm0" (formula "17") (term "0,0,1,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,1,1")) - (rule "add_literals" (formula "17") (term "1,1,0,1,1")) - (rule "times_zero_1" (formula "17") (term "1,0,1,1")) - (rule "add_literals" (formula "17") (term "0,1,1")) - (rule "leq_literals" (formula "17") (term "1,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1")) - (rule "add_literals" (formula "17") (term "0,0,1")) - (rule "add_zero_left" (formula "17") (term "0,1")) - (rule "applyEq" (formula "17") (term "1,0,0") (ifseqformula "20")) - (rule "inEqSimp_invertInEq1" (formula "17") (term "1")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1")) - (rule "times_zero_2" (formula "17") (term "1,1")) - (rule "polySimp_elimOne" (formula "17") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "21")) - (rule "qeq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "17") (term "0,0")) - (rule "commute_or_2" (formula "17") (term "0,0,0")) - (rule "cnf_rightDist" (formula "16") (term "0")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "16") (term "0")) - (rule "commute_or" (formula "17") (term "0")) - (rule "commute_or" (formula "16") (term "0,0")) - (rule "commute_or_2" (formula "18") (term "0,0,0,0")) - (rule "shift_paren_or" (formula "18") (term "0,0,0,0,0")) - (rule "allLeft" (formula "4") (inst "t=add(Z(1(#)), i_0)")) + (rule "allLeft" (formula "4") (inst "t=i_0:int")) (rule "inEqSimp_commuteGeq" (formula "4") (term "1")) - (rule "inEqSimp_homoInEq0" (formula "4") (term "1,0")) - (rule "polySimp_mulComm0" (formula "4") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "4") (term "1,0,1,0")) - (rule "mul_literals" (formula "4") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "4") (term "0,1,0")) - (rule "add_literals" (formula "4") (term "0,0,1,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "4") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "4") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "4") (term "0,1,0")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "1,0") (ifseqformula "2")) - (rule "qeq_literals" (formula "4") (term "0,1,0")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "1") (ifseqformula "3")) - (rule "inEqSimp_homoInEq1" (formula "4") (term "0,1")) - (rule "polySimp_mulComm0" (formula "4") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "4") (term "1,0,0,1")) - (rule "mul_literals" (formula "4") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "4") (term "0,0,1")) - (rule "polySimp_addComm1" (formula "4") (term "0,0,0,1")) - (rule "add_literals" (formula "4") (term "0,0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "4") (term "0,0,1")) - (rule "add_literals" (formula "4") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "4") (term "1,0,0,1")) - (rule "add_literals" (formula "4") (term "0,0,1")) - (rule "leq_literals" (formula "4") (term "0,1")) + (rule "applyEq" (formula "4") (term "1,0,0,0") (ifseqformula "1")) + (rule "replace_known_right" (formula "4") (term "0,0") (ifseqformula "23")) (builtin "One Step Simplification" (formula "4")) - (rule "allLeft" (formula "5") (inst "t=add(Z(neglit(1(#))), - select<[int]>(heap, self, LinkedList::#size))")) - (rule "inEqSimp_homoInEq1" (formula "5") (term "1")) - (rule "polySimp_mulComm0" (formula "5") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "5") (term "1,0,1")) - (rule "mul_literals" (formula "5") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "5") (term "0,1")) - (rule "polySimp_addComm0" (formula "5") (term "0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "5") (term "0,1")) - (rule "add_literals" (formula "5") (term "1,1,0,1")) - (rule "times_zero_1" (formula "5") (term "1,0,1")) - (rule "add_literals" (formula "5") (term "0,1")) - (rule "leq_literals" (formula "5") (term "1")) + (rule "allLeft" (formula "5") (inst "t=i_0_0:int")) + (rule "inEqSimp_commuteGeq" (formula "5") (term "1")) + (rule "applyEq" (formula "5") (term "1,0,0,0") (ifseqformula "11")) + (rule "replace_known_right" (formula "5") (term "0,0") (ifseqformula "24")) (builtin "One Step Simplification" (formula "5")) - (rule "inEqSimp_homoInEq0" (formula "5") (term "1")) - (rule "polySimp_mulComm0" (formula "5") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "5") (term "1,0,1")) - (rule "mul_literals" (formula "5") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "5") (term "0,1")) - (rule "add_literals" (formula "5") (term "0,0,1")) - (rule "add_zero_left" (formula "5") (term "0,1")) - (rule "applyEq" (formula "5") (term "1,0,0") (ifseqformula "24")) - (rule "inEqSimp_invertInEq1" (formula "5") (term "1")) - (rule "mul_literals" (formula "5") (term "1,1")) - (rule "polySimp_mulLiterals" (formula "5") (term "0,1")) - (rule "polySimp_elimOne" (formula "5") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "5") (term "1") (ifseqformula "25")) - (rule "qeq_literals" (formula "5") (term "0,1")) + (rule "inEqSimp_contradInEq1" (formula "5") (term "0") (ifseqformula "9")) + (rule "qeq_literals" (formula "5") (term "0,0")) (builtin "One Step Simplification" (formula "5")) - (rule "allLeft" (formula "6") (inst "t=Z(0(#))")) - (rule "leq_literals" (formula "6") (term "1,0")) - (builtin "One Step Simplification" (formula "6")) - (rule "inEqSimp_commuteGeq" (formula "6") (term "1")) - (rule "applyEq" (formula "6") (term "1,0,0") (ifseqformula "24")) - (rule "inEqSimp_contradInEq1" (formula "6") (term "1") (ifseqformula "26")) - (rule "qeq_literals" (formula "6") (term "0,1")) - (builtin "One Step Simplification" (formula "6")) - (rule "allLeft" (formula "7") (inst "t=i_0_0")) - (rule "inEqSimp_commuteGeq" (formula "7") (term "1")) - (rule "applyEq" (formula "7") (term "1,0,0,0") (ifseqformula "13")) - (rule "replace_known_right" (formula "7") (term "0,0") (ifseqformula "30")) - (builtin "One Step Simplification" (formula "7")) - (rule "inEqSimp_contradInEq1" (formula "7") (term "0") (ifseqformula "11")) - (rule "qeq_literals" (formula "7") (term "0,0")) - (builtin "One Step Simplification" (formula "7")) - (rule "inEqSimp_contradInEq1" (formula "7") (ifseqformula "12")) - (rule "andLeft" (formula "7")) - (rule "inEqSimp_homoInEq1" (formula "7")) - (rule "polySimp_pullOutFactor1b" (formula "7") (term "0")) - (rule "add_literals" (formula "7") (term "1,1,0")) - (rule "times_zero_1" (formula "7") (term "1,0")) - (rule "add_literals" (formula "7") (term "0")) - (rule "leq_literals" (formula "7")) - (rule "closeFalse" (formula "7")) + (rule "inEqSimp_contradInEq1" (formula "4") (term "0") (ifseqformula "2")) + (rule "qeq_literals" (formula "4") (term "0,0")) + (builtin "One Step Simplification" (formula "4")) + (rule "inEqSimp_contradInEq0" (formula "10") (ifseqformula "5")) + (rule "andLeft" (formula "10")) + (rule "inEqSimp_homoInEq1" (formula "10")) + (rule "polySimp_pullOutFactor1b" (formula "10") (term "0")) + (rule "add_literals" (formula "10") (term "1,1,0")) + (rule "times_zero_1" (formula "10") (term "1,0")) + (rule "add_literals" (formula "10") (term "0")) + (rule "leq_literals" (formula "10")) + (rule "closeFalse" (formula "10")) ) (branch "(Node)self.nodeseq[i_0] = n_2 FALSE" - (rule "applyEqReverse" (formula "27") (term "1,1") (ifseqformula "2")) + (rule "applyEqReverse" (formula "27") (term "1,1,0,0") (ifseqformula "2")) (rule "hideAuxiliaryEq" (formula "2")) - (rule "eqSymm" (formula "26") (term "1")) (rule "replace_known_right" (formula "1") (term "0,0") (ifseqformula "22")) (builtin "One Step Simplification" (formula "1")) - (rule "applyEqReverse" (formula "26") (term "1,1,0,0") (ifseqformula "1")) + (rule "applyEqReverse" (formula "26") (term "1,1") (ifseqformula "1")) (rule "hideAuxiliaryEq" (formula "1")) + (rule "eqSymm" (formula "25") (term "1")) (rule "all_pull_out1" (formula "15") (term "0,1,0")) - (rule "cut_direct" (formula "25") (term "0,0,0,0")) - (branch "CUT: (Node)self.nodeseq[i_0] = null TRUE" - (builtin "One Step Simplification" (formula "26")) - (rule "false_right" (formula "26")) - (rule "applyEq" (formula "22") (term "0") (ifseqformula "1")) - (rule "eqSymm" (formula "22")) - (rule "all_pull_out0" (formula "16") (term "1,0")) - (rule "shift_paren_and" (formula "16") (term "0,1,0")) - (rule "all_pull_out3" (formula "16") (term "0")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "shift_paren_or" (formula "17") (term "0")) - (rule "commute_or_2" (formula "17") (term "0,0")) - (rule "inEqSimp_or_weaken3" (formula "17") (term "0")) - (rule "polySimp_addAssoc" (formula "17") (term "1,0,1,0")) - (rule "add_literals" (formula "17") (term "0,1,0,1,0")) - (rule "add_zero_left" (formula "17") (term "1,0,1,0")) - (builtin "One Step Simplification" (formula "17")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "17") (term "0")) - (builtin "One Step Simplification" (formula "17")) - (rule "inEqSimp_homoInEq0" (formula "17") (term "0,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,0,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,0,1")) - (rule "add_literals" (formula "17") (term "0,0,0,1")) - (rule "add_zero_left" (formula "17") (term "0,0,1")) - (rule "inEqSimp_homoInEq1" (formula "17") (term "1,1")) - (rule "polySimp_mulComm0" (formula "17") (term "1,0,1,1")) - (rule "polySimp_rightDist" (formula "17") (term "1,0,1,1")) - (rule "mul_literals" (formula "17") (term "0,1,0,1,1")) - (rule "polySimp_addAssoc" (formula "17") (term "0,1,1")) - (rule "polySimp_addComm0" (formula "17") (term "0,0,1,1")) - (rule "polySimp_pullOutFactor1b" (formula "17") (term "0,1,1")) - (rule "add_literals" (formula "17") (term "1,1,0,1,1")) - (rule "times_zero_1" (formula "17") (term "1,0,1,1")) - (rule "add_literals" (formula "17") (term "0,1,1")) - (rule "leq_literals" (formula "17") (term "1,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "applyEq" (formula "17") (term "1,0,0") (ifseqformula "20")) - (rule "inEqSimp_invertInEq1" (formula "17") (term "1")) - (rule "polySimp_mulLiterals" (formula "17") (term "0,1")) - (rule "times_zero_2" (formula "17") (term "1,1")) - (rule "polySimp_elimOne" (formula "17") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "17") (term "1") (ifseqformula "21")) - (rule "qeq_literals" (formula "17") (term "0,1")) - (builtin "One Step Simplification" (formula "17")) - (rule "cnf_rightDist" (formula "16") (term "0,0")) - (rule "distr_forallAnd" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "17") (term "0,0")) - (rule "commute_or_2" (formula "17") (term "0,0,0")) - (rule "cnf_rightDist" (formula "16") (term "0")) - (rule "distr_forallAnd" (formula "16")) - (rule "andLeft" (formula "16")) - (rule "commute_or_2" (formula "16") (term "0")) - (rule "commute_or" (formula "17") (term "0")) - (rule "commute_or" (formula "16") (term "0,0")) - (rule "commute_or_2" (formula "18") (term "0,0,0,0")) - (rule "shift_paren_or" (formula "18") (term "0,0,0,0,0")) - (rule "allLeft" (formula "4") (inst "t=i_0")) - (rule "inEqSimp_commuteGeq" (formula "4") (term "1")) - (rule "applyEq" (formula "4") (term "1,0,0,0") (ifseqformula "1")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "1,0") (ifseqformula "2")) - (rule "qeq_literals" (formula "4") (term "0,1,0")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "1") (ifseqformula "3")) - (rule "inEqSimp_homoInEq1" (formula "4") (term "0,1")) - (rule "polySimp_pullOutFactor1b" (formula "4") (term "0,0,1")) - (rule "add_literals" (formula "4") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "4") (term "1,0,0,1")) - (rule "add_literals" (formula "4") (term "0,0,1")) - (rule "leq_literals" (formula "4") (term "0,1")) - (builtin "One Step Simplification" (formula "4")) - (rule "allLeft" (formula "5") (inst "t=add(Z(neglit(1(#))), - select<[int]>(heap, self, LinkedList::#size))")) - (rule "inEqSimp_homoInEq0" (formula "5") (term "1,0")) - (rule "polySimp_mulComm0" (formula "5") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "5") (term "1,0,1,0")) - (rule "mul_literals" (formula "5") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "5") (term "0,1,0")) - (rule "add_literals" (formula "5") (term "0,0,1,0")) - (rule "add_zero_left" (formula "5") (term "0,1,0")) - (rule "inEqSimp_homoInEq1" (formula "5") (term "1")) - (rule "polySimp_mulComm0" (formula "5") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "5") (term "1,0,1")) - (rule "mul_literals" (formula "5") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "5") (term "0,1")) - (rule "polySimp_addComm0" (formula "5") (term "0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "5") (term "0,1")) - (rule "add_literals" (formula "5") (term "1,1,0,1")) - (rule "times_zero_1" (formula "5") (term "1,0,1")) - (rule "add_literals" (formula "5") (term "0,1")) - (rule "leq_literals" (formula "5") (term "1")) - (builtin "One Step Simplification" (formula "5")) - (rule "applyEq" (formula "5") (term "1,0,0") (ifseqformula "24")) - (rule "inEqSimp_invertInEq1" (formula "5") (term "1")) - (rule "polySimp_mulLiterals" (formula "5") (term "0,1")) - (rule "times_zero_2" (formula "5") (term "1,1")) - (rule "polySimp_elimOne" (formula "5") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "5") (term "1") (ifseqformula "25")) - (rule "qeq_literals" (formula "5") (term "0,1")) - (builtin "One Step Simplification" (formula "5")) - (rule "allLeft" (formula "6") (inst "t=Z(0(#))")) - (rule "leq_literals" (formula "6") (term "1,0")) - (builtin "One Step Simplification" (formula "6")) - (rule "inEqSimp_commuteGeq" (formula "6") (term "1")) - (rule "applyEq" (formula "6") (term "1,0,0") (ifseqformula "24")) - (rule "inEqSimp_contradInEq1" (formula "6") (term "1") (ifseqformula "26")) - (rule "qeq_literals" (formula "6") (term "0,1")) - (builtin "One Step Simplification" (formula "6")) - (rule "allLeft" (formula "7") (inst "t=i_0_0")) - (rule "inEqSimp_commuteGeq" (formula "7") (term "1")) - (rule "applyEq" (formula "7") (term "1,0,0,0") (ifseqformula "13")) - (rule "replace_known_right" (formula "7") (term "0,0") (ifseqformula "30")) - (builtin "One Step Simplification" (formula "7")) - (rule "inEqSimp_contradInEq1" (formula "7") (term "1") (ifseqformula "12")) - (rule "inEqSimp_homoInEq1" (formula "7") (term "0,1")) - (rule "polySimp_pullOutFactor1b" (formula "7") (term "0,0,1")) - (rule "add_literals" (formula "7") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "7") (term "1,0,0,1")) - (rule "add_literals" (formula "7") (term "0,0,1")) - (rule "leq_literals" (formula "7") (term "0,1")) - (builtin "One Step Simplification" (formula "7")) - (rule "inEqSimp_contradInEq0" (formula "11") (ifseqformula "7")) - (rule "qeq_literals" (formula "11") (term "0")) - (builtin "One Step Simplification" (formula "11")) - (rule "closeFalse" (formula "11")) - ) - (branch "CUT: (Node)self.nodeseq[i_0] = null FALSE" - (builtin "One Step Simplification" (formula "26")) - (rule "all_pull_out0" (formula "15") (term "1,0")) - (rule "shift_paren_and" (formula "15") (term "0,1,0")) - (rule "all_pull_out3" (formula "15") (term "0")) - (rule "cnf_rightDist" (formula "15") (term "0,0")) - (rule "distr_forallAnd" (formula "15") (term "0")) - (builtin "One Step Simplification" (formula "15")) - (rule "distr_forallAnd" (formula "15")) - (rule "andLeft" (formula "15")) - (rule "shift_paren_or" (formula "16") (term "0")) - (rule "commute_or_2" (formula "16") (term "0,0")) - (rule "inEqSimp_or_weaken3" (formula "16") (term "0")) - (rule "polySimp_addAssoc" (formula "16") (term "1,0,1,0")) - (rule "add_literals" (formula "16") (term "0,1,0,1,0")) - (rule "add_zero_left" (formula "16") (term "1,0,1,0")) - (builtin "One Step Simplification" (formula "16")) - (rule "cnf_rightDist" (formula "15") (term "0,0")) - (rule "distr_forallAnd" (formula "15") (term "0")) - (builtin "One Step Simplification" (formula "15")) - (rule "distr_forallAnd" (formula "15")) - (rule "andLeft" (formula "15")) - (rule "commute_or_2" (formula "16") (term "0")) - (builtin "One Step Simplification" (formula "16")) - (rule "inEqSimp_homoInEq1" (formula "16") (term "1,1")) - (rule "polySimp_mulComm0" (formula "16") (term "1,0,1,1")) - (rule "polySimp_rightDist" (formula "16") (term "1,0,1,1")) - (rule "mul_literals" (formula "16") (term "0,1,0,1,1")) - (rule "polySimp_addAssoc" (formula "16") (term "0,1,1")) - (rule "polySimp_addComm0" (formula "16") (term "0,0,1,1")) - (rule "polySimp_pullOutFactor1b" (formula "16") (term "0,1,1")) - (rule "add_literals" (formula "16") (term "1,1,0,1,1")) - (rule "times_zero_1" (formula "16") (term "1,0,1,1")) - (rule "add_literals" (formula "16") (term "0,1,1")) - (rule "leq_literals" (formula "16") (term "1,1")) - (builtin "One Step Simplification" (formula "16")) - (rule "inEqSimp_homoInEq0" (formula "16") (term "1")) - (rule "polySimp_mulComm0" (formula "16") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "16") (term "1,0,1")) - (rule "mul_literals" (formula "16") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "16") (term "0,1")) - (rule "add_literals" (formula "16") (term "0,0,1")) - (rule "add_zero_left" (formula "16") (term "0,1")) - (rule "applyEq" (formula "16") (term "1,0,0") (ifseqformula "19")) - (rule "inEqSimp_invertInEq1" (formula "16") (term "1")) - (rule "polySimp_mulLiterals" (formula "16") (term "0,1")) - (rule "mul_literals" (formula "16") (term "1,1")) - (rule "polySimp_elimOne" (formula "16") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "16") (term "1") (ifseqformula "20")) - (rule "qeq_literals" (formula "16") (term "0,1")) - (builtin "One Step Simplification" (formula "16")) - (rule "cnf_rightDist" (formula "15") (term "0,0")) - (rule "distr_forallAnd" (formula "15") (term "0")) - (builtin "One Step Simplification" (formula "15")) - (rule "distr_forallAnd" (formula "15")) - (rule "andLeft" (formula "15")) - (rule "commute_or_2" (formula "16") (term "0,0")) - (rule "commute_or_2" (formula "16") (term "0,0,0")) - (rule "cnf_rightDist" (formula "15") (term "0")) - (rule "distr_forallAnd" (formula "15")) - (rule "andLeft" (formula "15")) - (rule "commute_or_2" (formula "15") (term "0")) - (rule "commute_or" (formula "16") (term "0")) - (rule "commute_or" (formula "15") (term "0,0")) - (rule "commute_or_2" (formula "17") (term "0,0,0,0")) - (rule "shift_paren_or" (formula "17") (term "0,0,0,0,0")) - (rule "allLeft" (formula "3") (inst "t=i_0")) - (rule "inEqSimp_commuteGeq" (formula "3") (term "1")) - (rule "inEqSimp_contradInEq1" (formula "3") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "3") (term "0,1")) - (rule "polySimp_pullOutFactor1b" (formula "3") (term "0,0,1")) - (rule "add_literals" (formula "3") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "3") (term "1,0,0,1")) - (rule "add_literals" (formula "3") (term "0,0,1")) - (rule "leq_literals" (formula "3") (term "0,1")) - (builtin "One Step Simplification" (formula "3")) - (rule "inEqSimp_contradInEq1" (formula "3") (term "1") (ifseqformula "1")) - (rule "qeq_literals" (formula "3") (term "0,1")) - (builtin "One Step Simplification" (formula "3")) - (rule "allLeft" (formula "4") (inst "t=add(Z(1(#)), i_0)")) - (rule "inEqSimp_commuteGeq" (formula "4") (term "1")) - (rule "inEqSimp_homoInEq0" (formula "4") (term "1,0")) - (rule "polySimp_mulComm0" (formula "4") (term "1,0,1,0")) - (rule "polySimp_rightDist" (formula "4") (term "1,0,1,0")) - (rule "mul_literals" (formula "4") (term "0,1,0,1,0")) - (rule "polySimp_addAssoc" (formula "4") (term "0,1,0")) - (rule "add_literals" (formula "4") (term "0,0,1,0")) - (rule "inEqSimp_sepNegMonomial1" (formula "4") (term "1,0")) - (rule "polySimp_mulLiterals" (formula "4") (term "0,1,0")) - (rule "polySimp_elimOne" (formula "4") (term "0,1,0")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "1,0") (ifseqformula "1")) - (rule "qeq_literals" (formula "4") (term "0,1,0")) - (builtin "One Step Simplification" (formula "4")) - (rule "inEqSimp_contradInEq1" (formula "4") (term "1") (ifseqformula "2")) - (rule "inEqSimp_homoInEq1" (formula "4") (term "0,1")) - (rule "polySimp_mulComm0" (formula "4") (term "1,0,0,1")) - (rule "polySimp_rightDist" (formula "4") (term "1,0,0,1")) - (rule "mul_literals" (formula "4") (term "0,1,0,0,1")) - (rule "polySimp_addAssoc" (formula "4") (term "0,0,1")) - (rule "polySimp_addComm1" (formula "4") (term "0,0,0,1")) - (rule "add_literals" (formula "4") (term "0,0,0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "4") (term "0,0,1")) - (rule "add_literals" (formula "4") (term "1,1,0,0,1")) - (rule "times_zero_1" (formula "4") (term "1,0,0,1")) - (rule "add_literals" (formula "4") (term "0,0,1")) - (rule "leq_literals" (formula "4") (term "0,1")) - (builtin "One Step Simplification" (formula "4")) - (rule "allLeft" (formula "5") (inst "t=add(Z(neglit(1(#))), - select<[int]>(heap, self, LinkedList::#size))")) - (rule "inEqSimp_homoInEq1" (formula "5") (term "1")) - (rule "polySimp_mulComm0" (formula "5") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "5") (term "1,0,1")) - (rule "mul_literals" (formula "5") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "5") (term "0,1")) - (rule "polySimp_addComm0" (formula "5") (term "0,0,1")) - (rule "polySimp_pullOutFactor1b" (formula "5") (term "0,1")) - (rule "add_literals" (formula "5") (term "1,1,0,1")) - (rule "times_zero_1" (formula "5") (term "1,0,1")) - (rule "add_zero_right" (formula "5") (term "0,1")) - (rule "leq_literals" (formula "5") (term "1")) - (builtin "One Step Simplification" (formula "5")) - (rule "inEqSimp_homoInEq0" (formula "5") (term "1")) - (rule "polySimp_mulComm0" (formula "5") (term "1,0,1")) - (rule "polySimp_rightDist" (formula "5") (term "1,0,1")) - (rule "mul_literals" (formula "5") (term "0,1,0,1")) - (rule "polySimp_addAssoc" (formula "5") (term "0,1")) - (rule "add_literals" (formula "5") (term "0,0,1")) - (rule "add_zero_left" (formula "5") (term "0,1")) - (rule "applyEq" (formula "5") (term "1,0,0") (ifseqformula "24")) - (rule "inEqSimp_invertInEq1" (formula "5") (term "1")) - (rule "polySimp_mulLiterals" (formula "5") (term "0,1")) - (rule "mul_literals" (formula "5") (term "1,1")) - (rule "polySimp_elimOne" (formula "5") (term "0,1")) - (rule "inEqSimp_contradInEq1" (formula "5") (term "1") (ifseqformula "25")) - (rule "qeq_literals" (formula "5") (term "0,1")) - (builtin "One Step Simplification" (formula "5")) - (rule "allLeft" (formula "6") (inst "t=Z(0(#))")) - (rule "leq_literals" (formula "6") (term "1,0")) - (builtin "One Step Simplification" (formula "6")) - (rule "inEqSimp_commuteGeq" (formula "6") (term "1")) - (rule "applyEq" (formula "6") (term "1,0,0") (ifseqformula "24")) - (rule "inEqSimp_contradInEq1" (formula "6") (term "1") (ifseqformula "26")) - (rule "qeq_literals" (formula "6") (term "0,1")) - (builtin "One Step Simplification" (formula "6")) - (rule "allLeft" (formula "7") (inst "t=i_0_0")) - (rule "inEqSimp_commuteGeq" (formula "7") (term "1")) - (rule "applyEq" (formula "7") (term "1,0,0,0") (ifseqformula "13")) - (rule "replace_known_right" (formula "7") (term "0,0") (ifseqformula "31")) - (builtin "One Step Simplification" (formula "7")) - (rule "inEqSimp_contradInEq1" (formula "7") (term "0") (ifseqformula "11")) - (rule "qeq_literals" (formula "7") (term "0,0")) - (builtin "One Step Simplification" (formula "7")) - (rule "inEqSimp_contradInEq0" (formula "12") (ifseqformula "7")) - (rule "andLeft" (formula "12")) - (rule "inEqSimp_homoInEq1" (formula "12")) - (rule "polySimp_pullOutFactor1b" (formula "12") (term "0")) - (rule "add_literals" (formula "12") (term "1,1,0")) - (rule "times_zero_1" (formula "12") (term "1,0")) - (rule "add_zero_right" (formula "12") (term "0")) - (rule "leq_literals" (formula "12")) - (rule "closeFalse" (formula "12")) - ) + (rule "allLeft" (formula "3") (inst "t=i_0_0:int")) + (rule "inEqSimp_commuteGeq" (formula "3") (term "1")) + (rule "applyEq" (formula "3") (term "1,0,0,0") (ifseqformula "9")) + (rule "replace_known_right" (formula "3") (term "0,0") (ifseqformula "23")) + (builtin "One Step Simplification" (formula "3")) + (rule "inEqSimp_contradInEq1" (formula "3") (term "0") (ifseqformula "7")) + (rule "qeq_literals" (formula "3") (term "0,0")) + (builtin "One Step Simplification" (formula "3")) + (rule "inEqSimp_contradInEq0" (formula "8") (ifseqformula "3")) + (rule "andLeft" (formula "8")) + (rule "inEqSimp_homoInEq1" (formula "8")) + (rule "polySimp_pullOutFactor1b" (formula "8") (term "0")) + (rule "add_literals" (formula "8") (term "1,1,0")) + (rule "times_zero_1" (formula "8") (term "1,0")) + (rule "add_literals" (formula "8") (term "0")) + (rule "leq_literals" (formula "8")) + (rule "closeFalse" (formula "8")) ) ) ) @@ -3666,7 +4456,7 @@ (rule "closeFalse" (formula "7")) ) ) - (branch + (branch "Case 2" (builtin "One Step Simplification" (formula "10") (ifInst "" (formula "8"))) (rule "closeTrue" (formula "10")) ) @@ -3674,43 +4464,43 @@ ) ) ) - (branch + (branch "Case 2" (builtin "One Step Simplification" (formula "10")) (rule "closeTrue" (formula "10")) ) ) - (branch + (branch "Case 2" (builtin "One Step Simplification" (formula "10")) - (rule "allRight" (formula "10") (inst "sk=f_0")) - (rule "allRight" (formula "10") (inst "sk=o_0_0")) + (rule "allRight" (formula "10") (inst "sk=f_0:Field")) + (rule "allRight" (formula "10") (inst "sk=o_0_0:java.lang.Object")) (rule "orRight" (formula "10")) (rule "eqSymm" (formula "11")) - (rule "pullOutSelect" (formula "11") (term "0") (inst "selectSK=f_0_0")) + (rule "pullOutSelect" (formula "11") (term "0") (inst "selectSK=f_0_0:any")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) (rule "eqSymm" (formula "12")) (rule "eqSymm" (formula "1") (term "0,0,0")) (rule "eqSymm" (formula "1") (term "1,0,0")) - (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=f_0_1")) + (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=f_0_1:any")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) (rule "eqSymm" (formula "1") (term "0,0,0")) (rule "eqSymm" (formula "1") (term "1,0,0")) - (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=f_0_2")) + (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=f_0_2:any")) (rule "simplifySelectOfStore" (formula "1")) (builtin "One Step Simplification" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) (rule "eqSymm" (formula "1") (term "0,0,0")) (rule "eqSymm" (formula "1") (term "1,0,0")) - (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=f_0_3")) + (rule "pullOutSelect" (formula "1") (term "2,0") (inst "selectSK=f_0_3:any")) (rule "simplifySelectOfCreate" (formula "1")) (rule "castDel" (formula "1") (term "1,0")) (rule "eqSymm" (formula "1") (term "0,0,0,0")) (rule "replace_known_right" (formula "1") (term "0,1,0,0,0") (ifseqformula "12")) (builtin "One Step Simplification" (formula "1")) - (rule "Class_invariant_axiom_for_LinkedList" (formula "10") (inst "i=i") (inst "j=j") (inst "i_0=i_0") (ifseqformula "13")) + (rule "Class_invariant_axiom_for_LinkedList" (formula "10") (inst "i=i") (inst "i_0=i_0") (inst "j=j") (ifseqformula "13")) (builtin "One Step Simplification" (formula "10")) (rule "andLeft" (formula "10")) (rule "andLeft" (formula "10")) @@ -4153,7 +4943,7 @@ (builtin "One Step Simplification" (formula "16")) (rule "true_left" (formula "16")) (rule "allLeft" (formula "11") (inst "t=add(Z(neglit(1(#))), - select<[int]>(heap, self, LinkedList::#size))")) + select<[int]>(heap, self, LinkedList::#size)):int")) (rule "inEqSimp_homoInEq1" (formula "11") (term "1")) (rule "polySimp_mulComm0" (formula "11") (term "1,0,1")) (rule "polySimp_rightDist" (formula "11") (term "1,0,1")) @@ -4183,7 +4973,7 @@ (builtin "One Step Simplification" (formula "11")) (rule "notLeft" (formula "11")) (rule "allLeft" (formula "12") (inst "t=add(Z(neglit(1(#))), - select<[int]>(heap, self, LinkedList::#size))")) + select<[int]>(heap, self, LinkedList::#size)):int")) (rule "eqSymm" (formula "12") (term "1")) (rule "inEqSimp_homoInEq1" (formula "12") (term "1,0")) (rule "polySimp_mulComm0" (formula "12") (term "1,0,1,0")) @@ -4212,7 +5002,7 @@ (rule "inEqSimp_contradInEq1" (formula "12") (term "0") (ifseqformula "19")) (rule "qeq_literals" (formula "12") (term "0,0")) (builtin "One Step Simplification" (formula "12")) - (rule "allLeft" (formula "11") (inst "t=Z(0(#))")) + (rule "allLeft" (formula "11") (inst "t=Z(0(#)):int")) (rule "leq_literals" (formula "11") (term "1,0")) (builtin "One Step Simplification" (formula "11")) (rule "inEqSimp_commuteGeq" (formula "11") (term "1")) @@ -4221,7 +5011,7 @@ (rule "qeq_literals" (formula "11") (term "0,1")) (builtin "One Step Simplification" (formula "11")) (rule "notLeft" (formula "11")) - (rule "allLeft" (formula "13") (inst "t=Z(0(#))")) + (rule "allLeft" (formula "13") (inst "t=Z(0(#)):int")) (rule "leq_literals" (formula "13") (term "0,0")) (builtin "One Step Simplification" (formula "13")) (rule "eqSymm" (formula "13") (term "1")) @@ -4297,4 +5087,4 @@ (rule "closeFalse" (formula "1")) ) ) -} \ No newline at end of file +} From 6d8a1af04fd5dff4d15fe8ce8cb9332d726fb997 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Wed, 22 Jul 2026 17:12:26 +0200 Subject: [PATCH 15/15] Code quality and documentation changes (incorporate reviewer suggestions) --- .../de/uka/ilkd/key/java/ServiceCaches.java | 7 +++--- .../rule/match/vm/ElementaryUpdateHead.java | 7 +++--- .../BranchMultiplicationCountFeature.java | 8 ------- .../de/uka/ilkd/key/proof/rules/heapRules.key | 8 +------ .../de/uka/ilkd/key/nparser/taclets.old.txt | 10 +++++++- .../Taclet_selectOfCreateReduceConcrete.proof | 24 ++++++++++--------- 6 files changed, 30 insertions(+), 34 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java b/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java index 26b11049d5c..3fe2d7a376f 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java +++ b/key.core/src/main/java/de/uka/ilkd/key/java/ServiceCaches.java @@ -31,6 +31,7 @@ import org.key_project.prover.rules.Taclet; import org.key_project.prover.rules.instantiation.caches.AssumesFormulaInstantiationCache; import org.key_project.prover.sequent.PosInOccurrence; +import org.key_project.prover.sequent.SequentFormula; import org.key_project.util.ConcurrentLruCache; import org.key_project.util.collection.ImmutableSet; import org.key_project.util.collection.Pair; @@ -143,12 +144,12 @@ public class ServiceCaches implements SessionCaches { /** * Per-formula operator-occurrence summary for the quantifier instantiation tie-break (which * operators occur in a sequent formula, and which at proving polarity). A sequent step - * replaces few formulas, and the {@link org.key_project.prover.sequent.SequentFormula} objects + * replaces few formulas, and the {@link SequentFormula} objects * are immutable and shared across the sequents of a branch, so the summary is memoised per * formula rather than recomputed per sequent. The value is opaque here (an * {@code Instantiation.OccInfo}) to keep this package independent of the strategy package. */ - private final Map formulaOccurrenceCache = + private final Map formulaOccurrenceCache = new ConcurrentLruCache<>(10000); /** @@ -250,7 +251,7 @@ public final Map getMonomialCache() { return monomialCache; } - public final Map getFormulaOccurrenceCache() { + public final Map getFormulaOccurrenceCache() { return formulaOccurrenceCache; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java index 333d2606d48..209d6539d9a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/match/vm/ElementaryUpdateHead.java @@ -79,10 +79,9 @@ public MatchProgram compileHeadCheck() { } @Override - public @Nullable Object topOperatorDescriptor() { - // with a concrete left-hand side exactly one update operator is accepted (elementary - // updates are interned per left-hand side); with a schema-variable left-hand side many - // are, and no single family describes them + public @Nullable ElementaryUpdate topOperatorDescriptor() { + // interned per left-hand side: a concrete lhs fixes one operator, a schema-variable + // lhs accepts many, which no single family describes return lhsIsSchemaVariable ? null : op; } diff --git a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java index ca8305230e7..56ff1c59679 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java +++ b/key.core/src/main/java/de/uka/ilkd/key/strategy/feature/BranchMultiplicationCountFeature.java @@ -17,14 +17,6 @@ * further application only while that count stays within a limit. * *

- * A single application says nothing about whether a proof is saturating: the first one on a branch - * and the twentieth look alike, so a criterion that describes only the application cannot tell them - * apart. The branch it sits on does. On the Stipula bike obligation, which needs - * cross-multiplication to close, no branch reaches six applications; on the deposit obligation, - * where the rule saturates, the median application is the nineteenth on its branch. - *

- * - *

* The count is carried in the goal's strategy information rather than recomputed or held in a map. * A goal inherits the count of the node it grew from, so advancing costs one comparison, and * pruning restores the previous value through the undo method. A map keyed by node would instead diff --git a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key index d292fdbfc93..358ef23fb10 100644 --- a/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key +++ b/key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heapRules.key @@ -692,13 +692,7 @@ \assumes(==> o = null) \find(select<[beta]>(create(h, o), o, java.lang.Object::#$created)) - - (permissions:off) { - \replacewith((beta)TRUE) - }; - (permissions:on) { - \replacewith((beta)TRUE) - } + \replacewith((beta)TRUE) \heuristics(concrete) }; 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 153e55ee7f8..0d24751f3d0 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 21 09:39:34 CEST 2026 +# Date: Wed Jul 22 17:10:12 CEST 2026 == abortJavaCardTransactionAPI (abortJavaCardTransactionAPI) ========================================= abortJavaCardTransactionAPI { @@ -15918,6 +15918,14 @@ selectOfCreateReduce { \heuristics(simplify_select_concrete) Choices: programRules:Java} ----------------------------------------------------- +== selectOfCreateReduceConcrete (selectOfCreateReduceConcrete) ========================================= +selectOfCreateReduceConcrete { +\assumes ([]==>[equals(o,null)]) +\find(select<[beta]>(create(h,o),o,java.lang.Object::#$created)) +\sameUpdateLevel\replacewith(cast<[beta]>(TRUE)) +\heuristics(concrete) +Choices: programRules:Java} +----------------------------------------------------- == selectOfMemset (selectOfMemset) ========================================= selectOfMemset { \find(select<[beta]>(memset(h,s,x),o,f)) diff --git a/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof b/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof index acf64f07641..3d127118b0a 100644 --- a/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof +++ b/key.core/tacletProofs/heap/Taclet_selectOfCreateReduceConcrete.proof @@ -2,23 +2,26 @@ \settings { "Choice" : { - "JavaCard" : "JavaCard:on", + "JavaCard" : "JavaCard:off", "Strings" : "Strings:on", - "assertions" : "assertions:on", + "assertions" : "assertions:safe", "bigint" : "bigint:on", "finalFields" : "finalFields:immutable", + "floatRules" : "floatRules:strictfpOnly", "initialisation" : "initialisation:disableStaticInitialisation", "intRules" : "intRules:arithmeticSemanticsIgnoringOF", "integerSimplificationRules" : "integerSimplificationRules:full", "javaLoopTreatment" : "javaLoopTreatment:efficient", "mergeGenerateIsWeakeningGoal" : "mergeGenerateIsWeakeningGoal:off", - "modelFields" : "modelFields:showSatisfiability", + "methodExpansion" : "methodExpansion:modularOnly", + "modelFields" : "modelFields:treatAsAxiom", "moreSeqRules" : "moreSeqRules:off", "permissions" : "permissions:off", "programRules" : "programRules:Java", "reach" : "reach:on", "runtimeExceptions" : "runtimeExceptions:ban", - "sequences" : "sequences:on" + "sequences" : "sequences:on", + "soundDefaultContracts" : "soundDefaultContracts:on" }, "Labels" : { "UseOriginLabels" : true @@ -49,19 +52,19 @@ "BLOCK_OPTIONS_KEY" : "BLOCK_CONTRACT_INTERNAL", "CLASS_AXIOM_OPTIONS_KEY" : "CLASS_AXIOM_FREE", "DEP_OPTIONS_KEY" : "DEP_ON", - "LOOP_OPTIONS_KEY" : "LOOP_SCOPE_INV_TACLET", + "LOOP_OPTIONS_KEY" : "LOOP_INVARIANT", "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_ON", - "QUERY_NEW_OPTIONS_KEY" : "QUERY_OFF", + "QUERYAXIOM_OPTIONS_KEY" : "QUERYAXIOM_OFF", + "QUERY_NEW_OPTIONS_KEY" : "QUERY_RESTRICTED", "SPLITTING_OPTIONS_KEY" : "SPLITTING_DELAYED", "STOPMODE_OPTIONS_KEY" : "STOPMODE_DEFAULT", "SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER", "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY" : "SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF", - "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_FULL", + "TRIGGERS_OPTIONS_KEY" : "TRIGGERS_BEST", "USER_TACLETS_OPTIONS_KEY1" : "USER_TACLETS_OFF", "USER_TACLETS_OPTIONS_KEY2" : "USER_TACLETS_OFF", "USER_TACLETS_OPTIONS_KEY3" : "USER_TACLETS_OFF", @@ -80,12 +83,11 @@ } \proof { -(keyLog "0" (keyUser "bubel" ) (keyVersion "40f2ff40876dc6765d47e8d8cd9ca970f14235f7")) +(keyLog "0" (keyUser "bubel" ) (keyVersion "5424ffff7125e9ba1109fd87159ce5bc47e27763")) -(autoModeTime "17") +(autoModeTime "57") (branch "dummy ID" - (builtin "One Step Simplification" (formula "1")) (rule "impRight" (formula "1")) (rule "notLeft" (formula "1")) (rule "selectOfCreateReduce" (formula "1") (term "0") (ifseqformula "2"))