Avoid searches of principal occurrence by utilizing MatchJournal.Index
This commit is contained in:
parent
65f1198a60
commit
022a9c372e
|
|
@ -46,6 +46,18 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk> {
|
|||
|
||||
interface Index : Comparator<Pos> {
|
||||
fun activatingChunkOf(occ: Id<Occurrence>): Chunk?
|
||||
fun principalOccurrenceOf(chunk: Chunk): OccurrencePos?
|
||||
|
||||
// just go through two maps
|
||||
fun principalPos(occ: Id<Occurrence>): OccurrencePos? =
|
||||
activatingChunkOf(occ)?.let { principalOccurrenceOf(it) }
|
||||
|
||||
// The latest matched occurrence from match's head is (by definition)
|
||||
// the occurrence which activated this match.
|
||||
fun activationPos(match: RuleMatchEx): OccurrencePos? =
|
||||
match.signature().mapNotNull { occSig ->
|
||||
occSig?.let { principalPos(it) }
|
||||
}.maxWith(this) // compare positions: find latest
|
||||
}
|
||||
|
||||
data class View(val chunks: List<Chunk>, val nextChunkId: Int)
|
||||
|
|
@ -85,22 +97,23 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk> {
|
|||
&& other.entriesInChunk() == entriesInChunk()
|
||||
}
|
||||
|
||||
data class OccurrencePos(val occ: Occurrence, private val chunk: MatchJournal.Chunk, private val offset: Int): MatchJournal.Pos()
|
||||
data class OccurrencePos(val occ: Occurrence, private val chunk: Chunk, private val offset: Int): MatchJournal.Pos()
|
||||
{
|
||||
companion object {
|
||||
fun fromIndex(index: MatchJournal.Index, occ: Occurrence): OccurrencePos? {
|
||||
val idOcc = Id(occ)
|
||||
val chunk = index.activatingChunkOf(idOcc) ?: return null
|
||||
val i = chunk.entriesLog().indexOfFirst { entry ->
|
||||
val chunk = index.activatingChunkOf(idOcc)
|
||||
?: return null
|
||||
|
||||
val offset = chunk.entriesLog().indexOfFirst { entry ->
|
||||
Id(entry.occ) == idOcc && !entry.isDiscarded
|
||||
}
|
||||
val offset = i + 1
|
||||
return if (offset >= 0) OccurrencePos(occ, chunk, offset) else null
|
||||
}
|
||||
}
|
||||
|
||||
override fun chunk(): MatchJournal.Chunk = chunk
|
||||
override fun entriesInChunk(): Int = offset
|
||||
override fun entriesInChunk(): Int = offset + 1
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -232,9 +245,9 @@ internal open class MatchJournalImpl(
|
|||
|
||||
private class ChunkImpl(match: RuleMatch, id: Int, justifications: Justs) : MatchJournal.Chunk(match, id, justifications)
|
||||
{
|
||||
var occurrences: MutableList<MatchJournal.Chunk.Entry> = mutableListOf()
|
||||
var occurrences: MutableList<Entry> = mutableListOf()
|
||||
|
||||
override fun entriesLog(): List<MatchJournal.Chunk.Entry> = occurrences
|
||||
override fun entriesLog(): List<Entry> = occurrences
|
||||
}
|
||||
|
||||
class IndexImpl(ispec: IncrementalProgramSpec, chunks: Iterable<MatchJournal.Chunk>): MatchJournal.Index
|
||||
|
|
@ -243,24 +256,32 @@ internal open class MatchJournalImpl(
|
|||
// only for principal constraints
|
||||
private val parentChunks: Map<Id<Occurrence>, MatchJournal.Chunk>
|
||||
|
||||
private val principalOccurrences: Map<Int, MatchJournal.OccurrencePos>
|
||||
|
||||
init {
|
||||
chunkOrder = HashMap<Int, Int>().apply {
|
||||
chunks.forEachIndexed { index, chunk -> put(chunk.id, index) }
|
||||
}
|
||||
|
||||
val m = HashMap<Id<Occurrence>, MatchJournal.Chunk>()
|
||||
chunks.forEach {chunk ->
|
||||
chunk.activatedLog().filter { occ ->
|
||||
ispec.isPrincipal(occ.constraint)
|
||||
}.forEach {occ ->
|
||||
m[Id(occ)] = chunk
|
||||
val m2 = HashMap<Int, MatchJournal.OccurrencePos>()
|
||||
chunks.forEach { chunk ->
|
||||
// actually there should be only a single principal occurrence, 'find' is enough
|
||||
chunk.entriesLog().forEachIndexed { index, e ->
|
||||
if (ispec.isPrincipal(e.occ.constraint) && !e.isDiscarded) {
|
||||
m[Id(e.occ)] = chunk
|
||||
m2[chunk.id] = MatchJournal.OccurrencePos(e.occ, chunk, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
parentChunks = m
|
||||
principalOccurrences = m2
|
||||
}
|
||||
|
||||
// todo: for non-principal find manually, walk through the whole journal... need it?
|
||||
override fun activatingChunkOf(occ: Id<Occurrence>): MatchJournal.Chunk? = parentChunks[occ]
|
||||
override fun activatingChunkOf(occ: Id<Occurrence>) = parentChunks[occ]
|
||||
|
||||
override fun principalOccurrenceOf(chunk: MatchJournal.Chunk) = principalOccurrences[chunk.id]
|
||||
|
||||
// todo: throw for invalid positions?
|
||||
override fun compare(lhs: MatchJournal.Pos, rhs: MatchJournal.Pos): Int {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package jetbrains.mps.logic.reactor.core.internal
|
|||
import jetbrains.mps.logic.reactor.core.*
|
||||
import jetbrains.mps.logic.reactor.evaluation.EvaluationTrace
|
||||
import jetbrains.mps.logic.reactor.evaluation.RuleMatch
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
import jetbrains.mps.logic.reactor.util.Id
|
||||
import jetbrains.mps.logic.reactor.util.Profiler
|
||||
|
|
@ -144,7 +143,7 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
|
||||
while (true) {
|
||||
// Does this chunk have principal occurrence and can activate anything at all?
|
||||
val pOcc = chunk.principalOccurrence()
|
||||
val pOcc = journalIndex.principalOccurrenceOf(chunk)?.occ
|
||||
if (pOcc != null) {
|
||||
|
||||
for (rule in rules) {
|
||||
|
|
@ -254,10 +253,11 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
val matches = dispatchingFront.matches().toList()
|
||||
val newCurrentMatches =
|
||||
// todo: assert that there can be no future matches on non-principal occurrences?
|
||||
if (isCurrent() || !active.isPrincipal())
|
||||
if (isCurrent() || !active.isPrincipal()) {
|
||||
matches
|
||||
else
|
||||
} else {
|
||||
postponeFutureMatches(matches)
|
||||
}
|
||||
val currentMatches = withPostponedMatches(active, newCurrentMatches)
|
||||
|
||||
val outStatus = currentMatches.fold(inStatus) { status, match ->
|
||||
|
|
@ -286,10 +286,13 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
|
||||
// Determines, filters out and enqueues (to execution queue) future matches. Returns only current matches.
|
||||
private fun postponeFutureMatches(matches: List<RuleMatchEx>): List<RuleMatchEx> {
|
||||
val currentMatches = mutableListOf<RuleMatchEx>()
|
||||
assert(matches.all { ispec.isPrincipal(it.rule()) })
|
||||
|
||||
val currentMatches = mutableListOf<RuleMatchEx>()
|
||||
for (m in matches) {
|
||||
val pos = latestMatchedOccurrence(m)
|
||||
// Returns null for matches with occurrences only from this session
|
||||
// because journalIndex indexes only previous session.
|
||||
val pos = journalIndex.activationPos(m)
|
||||
// if it is a future match
|
||||
if (pos != null && journalIndex.compare(lastIncrementalRootPos, pos) < 0) {
|
||||
val idOcc = Id(pos.occ)
|
||||
|
|
@ -302,16 +305,6 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
return currentMatches
|
||||
}
|
||||
|
||||
// The latest matched occurrence from match's head is (by definition) the occurrence which activated this match.
|
||||
// Returns null for matches with occurrences only from this session
|
||||
// (because journalIndex indexes only previous session).
|
||||
private fun latestMatchedOccurrence(match: RuleMatchEx): MatchJournal.OccurrencePos? =
|
||||
match.signature().mapNotNull { occSig ->
|
||||
occSig?.wrapped?.let { occ ->
|
||||
MatchJournal.OccurrencePos.fromIndex(journalIndex, occ)
|
||||
}
|
||||
}.maxWith(journalIndex) // compare positions: find latest
|
||||
|
||||
|
||||
private inline fun FeedbackStatus.then(action: (FeedbackStatus) -> FeedbackStatus) : FeedbackStatus =
|
||||
if (operational) action(this) else this
|
||||
|
|
@ -352,9 +345,6 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
|
|||
}
|
||||
|
||||
|
||||
private fun MatchJournal.Chunk.principalOccurrence(): Occurrence? =
|
||||
activatedLog().find { ispec.isPrincipal(it.constraint) }
|
||||
|
||||
private fun Occurrence.isPrincipal() = ispec.isPrincipal(this.constraint())
|
||||
|
||||
private fun Justs.intersects(other: Iterable<Int>): Boolean = other.any { this.contains(it) }
|
||||
|
|
|
|||
Loading…
Reference in New Issue