From 9aaf35561adc7371c533471a6ec0bd99ff3c8d41 Mon Sep 17 00:00:00 2001 From: Grigorii Kirgizov Date: Mon, 20 Jan 2020 20:22:12 +0300 Subject: [PATCH] Mem opt: store RuleMatchers only for principal rules between sessions. Add a test for incr processing. The number of preserved matchers is around 4-10 times less. The added test is an example of programs handled incorrectly with this opt. Fails now. --- .../mps/logic/reactor/core/RuleMatcher.kt | 2 + .../core/internal/ConstraintsProcessing.kt | 5 +- .../core/internal/ReteRuleMatcherImpl.kt | 2 + .../reactor/core/internal/RuleMatcherImpl.kt | 2 + reactor/Test/test/TestIncrementalProgram.kt | 57 +++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt index 856d14e3..6725e8aa 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt @@ -33,6 +33,8 @@ import jetbrains.mps.logic.reactor.program.Rule */ interface RuleMatcher { + fun rule(): Rule + fun newProbe(): RuleMatchingProbe fun probe(): RuleMatchingProbe diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt index 6c2392e1..6d30adfa 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ConstraintsProcessing.kt @@ -200,7 +200,10 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di val histView = view() resetStore() // clear observers val rules = ArrayList().apply { ruleIndex.forEach { add(it) } } - return SessionTokenImpl(histView, rules, dispatchingFront.state(), logicalState.clear()) + val principalState = dispatchingFront.state().filterValues { ruleMatcher -> + ispec.isPrincipal(ruleMatcher.rule()) + } + return SessionTokenImpl(histView, rules, principalState, logicalState.clear()) } /** diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt index 248d335b..284da833 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt @@ -56,6 +56,8 @@ internal class ReteRuleMatcherImpl(private var ruleLookup: RuleLookup, fun lookupRule(): Rule = ruleLookup.lookupRuleByTag(tag) ?: throw IllegalStateException("can't lookup rule by tag: '${tag}'") + override fun rule() = lookupRule() + override fun setRuleLookup(ruleLookup: RuleLookup) { this.ruleLookup = ruleLookup } override fun newProbe(): RuleMatchingProbe = ReteNetwork(head.size).also { probe = it } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/RuleMatcherImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/RuleMatcherImpl.kt index f8904475..7c8134b9 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/RuleMatcherImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/RuleMatcherImpl.kt @@ -43,6 +43,8 @@ internal class RuleMatcherImpl(private var ruleLookup: RuleLookup, fun lookupRule(): Rule = ruleLookup.lookupRuleByTag(tag) ?: throw IllegalStateException("can't lookup rule by tag: '${tag}'") + override fun rule() = lookupRule() + override fun setRuleLookup(ruleLookup: RuleLookup) { this.ruleLookup = ruleLookup } override fun newProbe(): RuleMatchingProbe = diff --git a/reactor/Test/test/TestIncrementalProgram.kt b/reactor/Test/test/TestIncrementalProgram.kt index 81cde2dc..e381d66b 100644 --- a/reactor/Test/test/TestIncrementalProgram.kt +++ b/reactor/Test/test/TestIncrementalProgram.kt @@ -1101,4 +1101,61 @@ class TestIncrementalProgram { } } + + @Test + fun completeNonprincipalRuleMatch() { + // Tests that state of non principal rules (i.e. their rule matchers) is preserved between sessions; + // that is, that partially matched non-principal rules can be fully matched in later sessions. + // This is a feature, not a necessity. For example, it could be mandated that + // such rules which should preserve their state can be only principal rules. + val progSpec = MockIncrProgSpec( + setOf("main", "foo", "bar"), + setOf(sym0("foo"), sym0("bar")) + ) + programWithRules( + rule("main", + headReplaced( + princConstraint("main") + ), + body( + princConstraint("foo"), + princConstraint("bar") + )), + rule("foo", + headReplaced( + princConstraint("foo") + ), + body( + constraint("hasBound"), + constraint("eliminateBound") + )), + // matches on two hasBound, but the first program produces only a single bound + rule("eliminateBounds", + headReplaced( + constraint("eliminateBound"), + constraint("hasBound"), + constraint("hasBound") + ), + body( + constraint("expected") + )) + ).launch("singleBound", progSpec) { result -> + result.storeView().constraintSymbols() shouldBe setOf(sym0("bar"), sym0("eliminateBound"), sym0("hasBound")) + result.storeView().allOccurrences().count() shouldBe 3 + + }.also { (builder, evalRes) -> + builder.programWithRules( + rule("bar", + headReplaced( + princConstraint("bar") + ), + body( + constraint("hasBound") + )) + ).relaunch("addSecondBound", progSpec, evalRes.token()) { result -> + result.storeView().constraintSymbols() shouldBe setOf(sym0("expected")) + result.storeView().allOccurrences().count() shouldBe 1 + } + } + } }