Don't expose InitialRule to RuleDiff. Add first test for rm algo stage.
This commit is contained in:
parent
0bfe9e8a47
commit
d7b7d40f8a
|
|
@ -66,9 +66,16 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
|
||||
private data class ExecPos(val pos: MatchJournal.Pos, val activeOcc: Occurrence)
|
||||
|
||||
private data class MatchCandidate(val rule: Rule, val occ: Occurrence, val occParentId: Int)
|
||||
|
||||
|
||||
// fixme: wtf, why idea's compiler complains???
|
||||
override fun index(): MatchJournal.Index = journalIndex
|
||||
|
||||
// Invalidation includes several activities:
|
||||
// - removing chunks (i.e. principal matches) corresponding to removed rules and chunks depending on them from journal
|
||||
// - reactivating occurrences that led to invalidated matches
|
||||
// - pruning invalidated occurrences and matches from Dispatcher's state
|
||||
fun invalidateByRules(ruleIds: Set<Any>) {
|
||||
val justificationRoots = mutableListOf<Int>()
|
||||
|
||||
|
|
@ -86,23 +93,25 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
|
||||
// We removed the match, so need to reactivate all still valid occurrences from the head
|
||||
// by definition of Chunk and principal rule, all occurrences from the head are principal
|
||||
// todo: check/assert it
|
||||
|
||||
val matchedOccs = chunk.match.allHeads() as Iterable<Occurrence>
|
||||
assert(matchedOccs.all { it.isPrincipal() })
|
||||
|
||||
val (invalidatedOccs, validOccs) = matchedOccs.partition { occ ->
|
||||
occ.justifications().intersects(justificationRoots)
|
||||
}
|
||||
|
||||
// todo: do need to reactivate only the main, matching~activating match?
|
||||
// (i.e. don't reactivate additional, inactive heads that only completed the match?)
|
||||
execQueue.addAll(validOccs.map { occ ->
|
||||
val chunkPos = journalIndex.activatingChunkOf(Id(occ))
|
||||
if (chunkPos != null) ExecPos(chunkPos, occ) else null
|
||||
}.filterNotNull())
|
||||
execQueue.addAll(validOccs.mapNotNull { occ ->
|
||||
journalIndex.activatingChunkOf(Id(occ))?.let { chunkPos ->
|
||||
ExecPos(chunkPos, occ)
|
||||
}
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Invalidating dependent chunks
|
||||
val toInvalidate = chunk.justifications.intersects(justificationRoots)
|
||||
if (toInvalidate) {
|
||||
// Remove the chunk from the journal
|
||||
|
|
@ -123,8 +132,6 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
}
|
||||
}
|
||||
|
||||
private data class MatchCandidate(val rule: Rule, val occ: Occurrence, val occParentId: Int)
|
||||
|
||||
private fun canMatch(rule: Rule, occ: Occurrence): Boolean =
|
||||
(rule.headKept() + rule.headReplaced()).find { it.symbol() == occ.constraint.symbol() } != null
|
||||
|
||||
|
|
@ -220,7 +227,7 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
}
|
||||
|
||||
fun snapshot(): SessionToken {
|
||||
return SessionToken(view(), ruleOrdering.ruleTags(), dispatchingFront.state())
|
||||
return SessionToken(view(), ruleOrdering.ruleTags, dispatchingFront.state())
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ import jetbrains.mps.logic.reactor.program.Rule
|
|||
internal class RuleOrdering(order: Iterable<Rule>): Comparator<Rule> {
|
||||
|
||||
private val ruleOrder: Map<Any, Int> = HashMap<Any, Int>().apply {
|
||||
put(MatchJournalImpl.InitRuleMatch.rule().uniqueTag(), -1)
|
||||
put(MatchJournalImpl.InitRuleMatch.rule().uniqueTag(), -1) // less than anything
|
||||
order.forEachIndexed { index, rule -> put(rule.uniqueTag(), index) }
|
||||
}
|
||||
|
||||
fun orderOf(rule: Rule): Int? = ruleOrder[rule.uniqueTag()]
|
||||
val ruleTags: Set<Any> = order.map { it.uniqueTag() }.toHashSet() // NB: without initial rule
|
||||
|
||||
fun ruleTags(): Set<Any> = ruleOrder.keys
|
||||
fun orderOf(rule: Rule): Int? = ruleOrder[rule.uniqueTag()]
|
||||
|
||||
override fun compare(lhs: Rule, rhs: Rule): Int {
|
||||
val lhsRuleOrder = orderOf(lhs)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import gnu.trove.set.TIntSet
|
||||
import gnu.trove.set.hash.TIntHashSet
|
||||
import jetbrains.mps.logic.reactor.core.*
|
||||
import jetbrains.mps.logic.reactor.core.internal.FeedbackStatus
|
||||
import jetbrains.mps.logic.reactor.evaluation.PredicateInvocation
|
||||
|
|
@ -84,6 +82,22 @@ private fun insertRulesInHandler(at: Int, name: String, rulesList: RulesList, va
|
|||
hb.toHandler()
|
||||
}
|
||||
|
||||
private fun removeRulesByIndices(at: Iterable<Int>, name: String, rulesList: RulesList): () -> RulesList = {
|
||||
val hb = HandlerBuilder(name)
|
||||
rulesList.rules().forEachIndexed { index, rule ->
|
||||
if (!at.contains(index)) hb.appendRule(rule)
|
||||
}
|
||||
hb.toHandler()
|
||||
}
|
||||
|
||||
private fun removeRulesByTags(tags: Iterable<Any>, name: String, rulesList: RulesList): () -> RulesList = {
|
||||
val hb = HandlerBuilder(name)
|
||||
rulesList.rules().forEach { rule ->
|
||||
if (!tags.contains(rule.uniqueTag())) hb.appendRule(rule)
|
||||
}
|
||||
hb.toHandler()
|
||||
}
|
||||
|
||||
private fun insertRulesInHandlerWhen(at: (Rule) -> Boolean, name: String, rulesList: RulesList, vararg ruleBlocks: () -> Rule): () -> RulesList =
|
||||
insertRulesInHandler(rulesList.rules().indexOfFirst(at), name, rulesList, * ruleBlocks)
|
||||
|
||||
|
|
@ -95,6 +109,12 @@ fun programWithRules(vararg ruleBuilders: () -> Rule): Builder =
|
|||
fun Builder.programWithRules(vararg ruleBuilders: () -> Rule): Builder =
|
||||
updateBuilder(this, arrayOf(updateHandler("test", rulesLists.first(), * ruleBuilders)))
|
||||
|
||||
fun Builder.removeRulesAt(at: Iterable<Int>): Builder =
|
||||
updateBuilder(this, arrayOf(removeRulesByIndices(at, "test", rulesLists.first())))
|
||||
|
||||
fun Builder.removeRules(tags: Iterable<Any>): Builder =
|
||||
updateBuilder(this, arrayOf(removeRulesByTags(tags, "test", rulesLists.first())))
|
||||
|
||||
fun Builder.insertRulesAt(at: Int, vararg ruleBuilders: () -> Rule): Builder =
|
||||
updateBuilder(this, arrayOf(insertRulesInHandler(at, "test", rulesLists.first(), * ruleBuilders)))
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ class TestIncrementalProgram {
|
|||
|
||||
private fun Iterable<Occurrence>.constraintSymbols() = this.map { it.constraint.symbol() }
|
||||
|
||||
private fun EvaluationResult.lastChunkSymbols() = this.lastChunk().activatedLog().constraintSymbols()
|
||||
|
||||
|
||||
@Test
|
||||
fun addNewMatchAtTheEnd() {
|
||||
|
|
@ -100,7 +102,7 @@ class TestIncrementalProgram {
|
|||
))
|
||||
).launch("addRule", progSpec) { result ->
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("foo"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("foo"))
|
||||
|
||||
}.also { (builder, evalRes) ->
|
||||
builder.programWithRules(
|
||||
|
|
@ -114,7 +116,7 @@ class TestIncrementalProgram {
|
|||
)
|
||||
).relaunch("test1", progSpec, evalRes.token()) { result ->
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("bar"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("bar"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("bar"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,7 +145,7 @@ class TestIncrementalProgram {
|
|||
)
|
||||
).launch("addRule", progSpec) { result ->
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("bar"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("bar"))
|
||||
|
||||
}.also { (builder, evalRes) ->
|
||||
builder.programWithRules(
|
||||
|
|
@ -157,7 +159,7 @@ class TestIncrementalProgram {
|
|||
)
|
||||
).relaunch("test1", progSpec, evalRes.token()) { result ->
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar"), sym0("baz"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("baz"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("baz"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -199,7 +201,7 @@ class TestIncrementalProgram {
|
|||
)
|
||||
).relaunch("test1", progSpec, evalRes.token()) { result ->
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar"), sym0("baz"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("baz"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("baz"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +225,7 @@ class TestIncrementalProgram {
|
|||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("main"))
|
||||
result.countChunks() shouldBe 2
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("foo"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("foo"))
|
||||
|
||||
}.also { (builder, evalRes) ->
|
||||
builder.programWithRules(
|
||||
|
|
@ -239,7 +241,7 @@ class TestIncrementalProgram {
|
|||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("main"), sym0("bar"))
|
||||
result.countChunks() shouldBe 3
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("bar"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("bar"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -315,7 +317,7 @@ class TestIncrementalProgram {
|
|||
).launch("initial run", progSpec) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("baz"), sym0("dummy"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("dummy"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("dummy"))
|
||||
|
||||
}.also { (builder, evalRes) ->
|
||||
val nPrincipalMatches = evalRes.countChunks()
|
||||
|
|
@ -332,7 +334,7 @@ class TestIncrementalProgram {
|
|||
).relaunch("test1", progSpec, evalRes.token()) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("bar"), sym0("baz"), sym0("dummy"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("dummy"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("dummy"))
|
||||
result.countChunks() shouldBe (1 + nPrincipalMatches)
|
||||
}
|
||||
}
|
||||
|
|
@ -509,7 +511,7 @@ class TestIncrementalProgram {
|
|||
// if "foobar" happens too early, "1st" occ won't be produced
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("start"), sym0("1st"), sym0("2nd"))
|
||||
// ensure right rule match order: the last chunk must contain "2nd"
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("2nd"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("2nd"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -568,10 +570,58 @@ class TestIncrementalProgram {
|
|||
|
||||
// if "foobar" happens too early, "1st" occ won't be produced
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar"), sym0("marker"))
|
||||
result.lastChunk().activatedLog().constraintSymbols() shouldBe listOf(sym0("marker"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("marker"))
|
||||
result.countChunks() shouldBe (2 + nPrincipalMatches) // +[.bar, foobar]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun rmSingleKeptMatch() {
|
||||
val progSpec = MockIncrProgSpec(
|
||||
setOf("main", "foo.bar", "foo.baz", "baz.qux"),
|
||||
setOf(sym0("foo"), sym0("baz"))
|
||||
)
|
||||
programWithRules(
|
||||
rule("main",
|
||||
headReplaced(
|
||||
constraint("main")
|
||||
),
|
||||
body(
|
||||
princConstraint("foo")
|
||||
)),
|
||||
rule("foo.baz",
|
||||
headReplaced(
|
||||
princConstraint("foo")
|
||||
),
|
||||
body(
|
||||
princConstraint("baz")
|
||||
)),
|
||||
rule("baz.qux",
|
||||
headKept(
|
||||
princConstraint("baz")
|
||||
),
|
||||
body(
|
||||
constraint("qux")
|
||||
)
|
||||
)
|
||||
).launch("initial run", progSpec) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("baz"), sym0("qux"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("qux"))
|
||||
|
||||
}.also { (builder, evalRes) ->
|
||||
val nPrincipalMatches = evalRes.countChunks()
|
||||
|
||||
// Insert rule before foo.baz: produce bar before discarding foo in foo.baz
|
||||
builder.removeRules(listOf("baz.qux"))
|
||||
.relaunch("removed", progSpec, evalRes.token()) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("baz"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("baz"))
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue