From 9a7838fdc7addaa7893f6fb9e0c3269df5bdc7df Mon Sep 17 00:00:00 2001 From: Grigorii Kirgizov Date: Wed, 8 May 2019 16:58:22 +0300 Subject: [PATCH] Add initial sketch of MatchHistory; add justifications to ConstraintOccurence interface --- .../mps/logic/reactor/core/Occurrence.kt | 16 ++- .../reactor/core/internal/MatchHistory.kt | 131 ++++++++++++++++++ .../evaluation/ConstraintOccurrence.java | 5 + 3 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt index 4fb26dab..ebe176c0 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Occurrence.kt @@ -16,6 +16,7 @@ package jetbrains.mps.logic.reactor.core +import gnu.trove.set.TIntSet import jetbrains.mps.logic.reactor.evaluation.ConstraintOccurrence import jetbrains.mps.logic.reactor.logical.Logical @@ -31,7 +32,8 @@ import jetbrains.mps.logic.reactor.program.Constraint data class Occurrence (val controller: Controller, val constraint: Constraint, val logicalContext: LogicalContext, - val arguments: List<*>) : + val arguments: List<*>, + val justifications: TIntSet?): ConstraintOccurrence, LogicalObserver { @@ -54,6 +56,8 @@ data class Occurrence (val controller: Controller, override fun logicalContext(): LogicalContext = logicalContext + override fun justifications(): TIntSet? = justifications + override fun valueUpdated(logical: Logical<*>) { if (alive) { controller.reactivate(this) @@ -81,12 +85,18 @@ data class Occurrence (val controller: Controller, fun Constraint.occurrence(controller: Controller, arguments: List<*>, + justifications: TIntSet?, logicalContext: LogicalContext): Occurrence = - Occurrence(controller, this, logicalContext, arguments) + Occurrence(controller, this, logicalContext, arguments, justifications) + +fun Constraint.occurrence(controller: Controller, + arguments: List<*>, + justifications: TIntSet?): Occurrence = + Occurrence(controller, this, noLogicalContext, arguments, justifications) fun Constraint.occurrence(controller: Controller, arguments: List<*>): Occurrence = - Occurrence(controller, this, noLogicalContext, arguments) + Occurrence(controller, this, noLogicalContext, arguments, null) private val noLogicalContext: LogicalContext = object: LogicalContext { override fun variable(metaLogical: MetaLogical): Logical? = null diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt new file mode 100644 index 00000000..6e0bc9ca --- /dev/null +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/MatchHistory.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2014-2019 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.mps.logic.reactor.core.internal + +import gnu.trove.set.TIntSet +import gnu.trove.set.hash.TIntHashSet +import jetbrains.mps.logic.reactor.core.Occurrence +import jetbrains.mps.logic.reactor.evaluation.RuleMatch +import org.jetbrains.kotlin.utils.mapToIndex + + +internal class MatchHistory() { + + class Chunk(val match: RuleMatch, val id: Int, headJustifications: TIntSet) { + data class Entry(val occ: Occurrence, val isDiscarded: Boolean = false) + + var occurrences: MutableList = mutableListOf() + val justifications = headJustifications.also { it.add(id) } + } + + class RemoveChunkIterator(val it: MutableListIterator): Iterator by it { + fun remove() = it.remove() + } + + fun removeIterator() = RemoveChunkIterator(hist.listIterator()) + + + fun logMatch(match: RuleMatchImpl) { + // If the set of justifications isn't empty, then we deal with principal constraint + val justs = match.headJustifications() + if (!justs.isEmpty) { + val newChunk = Chunk(match, nextChunkId++, justs) + pos.add(newChunk) + current = newChunk + } + + // Log discards + match.forEachReplaced {occ -> +// this.dispatchFringe = dispatchFringe.contract(occ) + current.occurrences.add(Chunk.Entry(occ, true)) + frameStack.current.store.discard(occ) + } + } + fun logOccurence(occ: Occurrence) { + current.occurrences.add(Chunk.Entry(occ)) + frameStack.current.store.store(occ) + } + + + data class HistoryPos(val frame: Frame, val chunk: Chunk, val occsRetained: Int = 0) + + // FrameStack API: currentFrame, push, reset + fun currentFrame() = HistoryPos(frameStack.current, current, current.occurrences.size) + fun push() = frameStack.push() + // Throw away recently added chunks and reset store accordingly + // NB: not checking that chunks are actually recently added + fun reset(timepoint: HistoryPos) { + frameStack.reset(timepoint.frame) + + while (timepoint.chunk != current && pos.hasPrevious()) { + pos.remove() + current = pos.previous() + } + current.occurrences = current.occurrences.take(timepoint.occsRetained) as MutableList + } + + fun rollTo(chunk: Chunk) { + while (chunk != current && pos.hasNext()) { + current = pos.next() + rollChunk() + } + } + private fun rollChunk() { + // 'apply' all occurrences of current chunk to the store + for (occSpec in current.occurrences) { + if (occSpec.isDiscarded) { + frameStack.current.store.discard(occSpec.occ) + } else { + frameStack.current.store.store(occSpec.occ) + } + } + } + + // Reset only store & history position, don't modify history + fun resetStore() { + frameStack.reset(Frame(frameStack)) + pos = hist.listIterator() + } + + // fixme: does belong to here? +// fun resetOrder() { order = hist.mapToIndex() } + + + private val hist: MutableList = mutableListOf() +// private var order: Map = emptyMap() + + // FIXME: add framestack to the class + // is it created along with MatchHistory? should be. + private val frameStack: FrameStack = FrameStack(null) //FIXME: ?provide storeView at construction + + private var pos: MutableListIterator = hist.listIterator() + // FIXME: provide initial chunk at construction + private lateinit var current: Chunk + + private var nextChunkId: Int = 0; + + +} + +private fun RuleMatch.headJustifications(): TIntSet { + val res: TIntSet = TIntHashSet() + this.matchHeadKept().forEach { it.justifications()?.let { res.addAll(it) } } + this.matchHeadReplaced().forEach { it.justifications()?.let { res.addAll(it) } } + return res +// return if (res.isEmpty) null else res +} + diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/ConstraintOccurrence.java b/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/ConstraintOccurrence.java index 6c6ab632..cf614d34 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/ConstraintOccurrence.java +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/evaluation/ConstraintOccurrence.java @@ -17,8 +17,10 @@ package jetbrains.mps.logic.reactor.evaluation; +import gnu.trove.set.TIntSet; import jetbrains.mps.logic.reactor.logical.LogicalContext; import jetbrains.mps.logic.reactor.program.Constraint; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -35,4 +37,7 @@ public interface ConstraintOccurrence { LogicalContext logicalContext(); + @Nullable + TIntSet justifications(); + }