Drop obsolete RuleMatcher implementation
This commit is contained in:
parent
7f55407c7a
commit
54b8d42e52
|
|
@ -19,7 +19,6 @@ package jetbrains.mps.logic.reactor.core
|
|||
import gnu.trove.list.TIntList
|
||||
import gnu.trove.list.array.TIntArrayList
|
||||
import jetbrains.mps.logic.reactor.core.internal.ReteRuleMatcherImpl
|
||||
import jetbrains.mps.logic.reactor.core.internal.RuleMatcherImpl
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,245 +0,0 @@
|
|||
/*
|
||||
* 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 jetbrains.mps.logic.reactor.core.*
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
import jetbrains.mps.logic.reactor.util.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
/**
|
||||
* This implementation of [RuleMatcher] is based on a simple algorithm which enumerates all possible
|
||||
* permutations of occurrences potentially matching the rule's head.
|
||||
*
|
||||
* Optimizations are in place to cut out permutations that don't fit for the reason that the arguments are mismatched
|
||||
* and/or logical variables are not unifiable with the substitutions calculated previously.
|
||||
*
|
||||
* @author Fedor Isakov
|
||||
*/
|
||||
internal class RuleMatcherImpl(private var ruleLookup: RuleLookup?,
|
||||
private val tag: Any) : RuleMatcher
|
||||
{
|
||||
|
||||
val head = lookupRule().run { ArrayList(headKept() + headReplaced()) }
|
||||
|
||||
val propagation = lookupRule().headReplaced().count() == 0
|
||||
|
||||
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 resetRuleLookup() { this.ruleLookup = null }
|
||||
|
||||
override fun newProbe(): RuleMatchingProbe =
|
||||
RuleMatchFront(emptyList(),
|
||||
emptyList(),
|
||||
Sets.of(IntArray(head.size).toSignature()),
|
||||
Sets.of(),
|
||||
Sets.of())
|
||||
.also { probe = it }
|
||||
|
||||
override fun probe(): RuleMatchingProbe = probe ?: newProbe()
|
||||
|
||||
private var probe: RuleMatchingProbe? = null
|
||||
|
||||
inner class RuleMatchFront(private val trunkNodes: List<MatchNode>,
|
||||
private val leafNodes: List<MatchNode>,
|
||||
private val leafSignatures: PersSet<Signature>,
|
||||
private val seenOccurrences: PersSet<Int>,
|
||||
private val consumedSignatures: PersSet<Signature>) : RuleMatchingProbe
|
||||
{
|
||||
override fun rule(): Rule = lookupRule()
|
||||
|
||||
override fun hasOccurrences(): Boolean = trunkNodes.size > 0 || leafNodes.size > 0
|
||||
|
||||
override fun matches(): Collection<RuleMatchImpl> =
|
||||
leafNodes
|
||||
.filter { node -> !consumedSignatures.contains(node.signature()) }
|
||||
.map { node -> node.toRuleMatch() }
|
||||
|
||||
override fun consume(ruleMatch: RuleMatchEx): RuleMatchingProbe =
|
||||
RuleMatchFront(trunkNodes,
|
||||
leafNodes,
|
||||
leafSignatures,
|
||||
seenOccurrences,
|
||||
consumedSignatures.put(ruleMatch.signatureArray().toSignature()))
|
||||
|
||||
override fun forget(ruleMatch: RuleMatchEx): RuleMatchingProbe =
|
||||
RuleMatchFront(trunkNodes,
|
||||
leafNodes,
|
||||
leafSignatures,
|
||||
seenOccurrences,
|
||||
consumedSignatures.without(ruleMatch.signatureArray().toSignature()))
|
||||
|
||||
override fun forget(occ: Occurrence): RuleMatchingProbe = with(this.contract(occ)) {
|
||||
val newConsumed = Sets.copyOf(consumedSignatures.filter{ !it.contains(occ.identity) })
|
||||
val newSeen = seenOccurrences.without(occ.identity)
|
||||
RuleMatchFront(trunkNodes,
|
||||
leafNodes,
|
||||
leafSignatures,
|
||||
newSeen,
|
||||
newConsumed)
|
||||
}
|
||||
|
||||
override fun expand(occ: Occurrence): RuleMatchingProbe =
|
||||
expand(occ, bitSetOfOnes(head.size))
|
||||
|
||||
/**
|
||||
* Expands the front by creating new leaf nodes that match the occurrence.
|
||||
* Mask specifies possible slots for the occurrence.
|
||||
*/
|
||||
override fun expand(occ: Occurrence, mask: BitSet, profiler: Profiler?): RuleMatchFront {
|
||||
val reactivated = seenOccurrences.contains(occ.identity)
|
||||
val newSeen = if (reactivated) seenOccurrences else seenOccurrences.put(occ.identity)
|
||||
val newTrunkNodes = ArrayList<MatchNode>(trunkNodes.size).apply { addAll(trunkNodes) }
|
||||
val newLeafNodes = arrayListOf<MatchNode>()
|
||||
var newSignatures = leafSignatures
|
||||
val expanded = ArrayList<MatchNode>()
|
||||
val effMask = mask.clone() as BitSet
|
||||
|
||||
for (node in (trunkNodes.asSequence() + BaseMatchNode())) {
|
||||
effMask.clear()
|
||||
effMask.or(mask)
|
||||
effMask.and(node.vacant)
|
||||
// val effMask = mask.copyApply { and(node.vacant) }
|
||||
// profiler.profile("expand_node1_${occ.constraint.symbol()}") {
|
||||
|
||||
if (!(effMask.isEmpty || node is MatchNode && node.hasOccurrence(occ))) {
|
||||
|
||||
expanded.clear()
|
||||
|
||||
val it = effMask.allSetBits()
|
||||
while (it.hasNext()) {
|
||||
val headIdx = it.next()
|
||||
val subst = if (node is MatchNode) node.subst else emptySubst()
|
||||
with(createOccurrenceMatcher(subst)) {
|
||||
if (matches(head[headIdx], occ)) {
|
||||
expanded.add(MatchNode(subst(), node, occ, headIdx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ex in expanded) {
|
||||
if (ex.leaf) {
|
||||
// ensure reactivated have effect
|
||||
val signature = ex.signature()
|
||||
if (!reactivated && newSignatures.contains(signature)) break
|
||||
// ...unless propagation (to avoid cycles)
|
||||
if (reactivated && propagation && consumedSignatures.contains(signature)) break
|
||||
newLeafNodes.add(ex)
|
||||
newSignatures = newSignatures.put(signature)
|
||||
}
|
||||
newTrunkNodes.add(ex)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RuleMatchFront(newTrunkNodes, newLeafNodes, newSignatures, newSeen, consumedSignatures)
|
||||
}
|
||||
|
||||
override fun contract(occ: Occurrence): RuleMatchFront {
|
||||
val newTrunkNodes = arrayListOf<MatchNode>()
|
||||
var newSignatures = Sets.of<Signature>()
|
||||
for (node in trunkNodes) {
|
||||
if (!node.hasOccurrence(occ)) {
|
||||
newTrunkNodes.add(node)
|
||||
if (node.leaf) {
|
||||
newSignatures = newSignatures.without(node.signature())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RuleMatchFront(newTrunkNodes, emptyList(), newSignatures, seenOccurrences, consumedSignatures)
|
||||
}
|
||||
|
||||
override fun forgetConsumed(occ: Occurrence): RuleMatchFront {
|
||||
val newConsumed = Sets.copyOf(consumedSignatures.filter{ !it.contains(occ.identity) })
|
||||
return RuleMatchFront(trunkNodes, leafNodes, leafSignatures, seenOccurrences, newConsumed) // NB: not modifying genId
|
||||
}
|
||||
|
||||
override fun forgetExpanded(occ: Occurrence): RuleMatchFront {
|
||||
val newSeen = seenOccurrences.without(occ.identity)
|
||||
return RuleMatchFront(trunkNodes, leafNodes, leafSignatures, newSeen, consumedSignatures) // NB: not modifying genId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open inner class BaseMatchNode(val vacant: BitSet = bitSetOfOnes(head.size)) {
|
||||
|
||||
/**
|
||||
* Folds the path to the root.
|
||||
*/
|
||||
inline protected fun <T> fold(init: T, action: (T, MatchNode) -> T): T {
|
||||
var rn = this
|
||||
var curr = init
|
||||
while (rn is MatchNode) {
|
||||
curr = action(curr, rn)
|
||||
rn = rn.parent
|
||||
}
|
||||
return curr
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inner class MatchNode(val subst: Subst,
|
||||
val parent: BaseMatchNode,
|
||||
val occurrence: Occurrence,
|
||||
val headIndex: Int) : BaseMatchNode(parent.vacant.clearBit(headIndex))
|
||||
{
|
||||
val leaf = vacant.cardinality() == 0
|
||||
|
||||
val trail: PersSet<Int> =
|
||||
if (parent is MatchNode) parent.trail.put(occurrence.identity) else Sets.of(occurrence.identity)
|
||||
|
||||
fun constraint(): Constraint = head[headIndex]
|
||||
|
||||
// a signature is a (partial) set of constraint occurrences that belong to this node
|
||||
fun signature(): Signature =
|
||||
fold(IntArray(head.size).toSignature()) { s, n ->
|
||||
s.apply { set(n.headIndex, n.occurrence.identity) } }
|
||||
|
||||
fun hasOccurrence(occ: Occurrence): Boolean = trail.contains(occ.identity)
|
||||
// fold(false) { flag, n -> flag || n.occurrence === occ } // referential equality !
|
||||
|
||||
fun matches() : Subst? =
|
||||
fold<OccurrenceMatcher?>(createOccurrenceMatcher(emptySubst())) { matcher, n ->
|
||||
matcher?.let {
|
||||
if (it.matches(n.constraint(), n.occurrence)) it else null
|
||||
}
|
||||
}?.subst()
|
||||
|
||||
fun toRuleMatch(): RuleMatchImpl {
|
||||
val matched: Array<Occurrence> =
|
||||
fold(arrayOfNulls<Occurrence>(head.size)) { arr, rn ->
|
||||
arr[rn.headIndex] = rn.occurrence; arr
|
||||
} as Array<Occurrence>
|
||||
|
||||
return RuleMatchImpl(lookupRule(),
|
||||
subst,
|
||||
ArrayList(matched.take(lookupRule().headKept().count())),
|
||||
ArrayList(matched.takeLast(lookupRule().headReplaced().count())))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue