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.
This commit is contained in:
Grigorii Kirgizov 2020-01-20 20:22:12 +03:00
parent 54fc91a031
commit 9aaf35561a
5 changed files with 67 additions and 1 deletions

View File

@ -33,6 +33,8 @@ import jetbrains.mps.logic.reactor.program.Rule
*/
interface RuleMatcher {
fun rule(): Rule
fun newProbe(): RuleMatchingProbe
fun probe(): RuleMatchingProbe

View File

@ -200,7 +200,10 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
val histView = view()
resetStore() // clear observers
val rules = ArrayList<Rule>().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())
}
/**

View File

@ -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 }

View File

@ -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 =

View File

@ -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
}
}
}
}