diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Dispatcher.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Dispatcher.kt index a0f64f93..3067d616 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Dispatcher.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Dispatcher.kt @@ -17,11 +17,8 @@ package jetbrains.mps.logic.reactor.core import gnu.trove.map.hash.TIntObjectHashMap - - -typealias DispatchingFrontState = Map - -internal fun emptyFrontState(): DispatchingFrontState = emptyMap() +import jetbrains.mps.logic.reactor.program.Rule +import java.util.IdentityHashMap /** * A front-end interface to [RuleMatcher]. @@ -30,38 +27,38 @@ internal fun emptyFrontState(): DispatchingFrontState = emptyMap() */ class Dispatcher (val ruleIndex: RuleIndex) { - private val ruletag2matcher = HashMap() + private val matcherByRule = IdentityHashMap() /** * Create new empty [DispatchingFront] ready to accept constraints. */ fun front() = DispatchingFront() - fun getOrCreateMatcher(ruleTag: Any): RuleMatcher = - ruletag2matcher.getOrPut(ruleTag) { createRuleMatcher(ruleIndex, ruleTag) } + fun getOrCreateMatcher(rule: Rule): RuleMatcher = + matcherByRule.getOrPut(rule) { createRuleMatcher(rule) } inner class DispatchingFront { - private val ruletag2probe : HashMap + private val probeByRule : IdentityHashMap - private val occId2tags : TIntObjectHashMap> + private val occId2tags : IdentityHashMap> private val matching: Iterable? constructor() { - this.ruletag2probe = hashMapOf() - this.occId2tags = TIntObjectHashMap() + this.probeByRule = IdentityHashMap() + this.occId2tags = IdentityHashMap() this.matching = null } private constructor(pred: DispatchingFront, matching: Iterable? = null) { - this.ruletag2probe = pred.ruletag2probe + this.probeByRule = pred.probeByRule this.occId2tags = pred.occId2tags this.matching = matching } - fun getOrCreateProbe(ruleTag: Any): RuleMatchingProbe = - ruletag2probe.getOrPut(ruleTag) { getOrCreateMatcher(ruleTag).probe() } + fun getOrCreateProbe(rule: Rule): RuleMatchingProbe = + probeByRule.getOrPut(rule) { getOrCreateMatcher(rule).probe() } /** * Returns all matches satisfied by the constraint occurrences received so far. @@ -72,9 +69,7 @@ class Dispatcher (val ruleIndex: RuleIndex) { allMatches.addAll(probe.matches()) } return allMatches - } - - fun state() : DispatchingFrontState = ruletag2matcher //.asMap() + } /** * Returns a [DispatchingFront] instance that is "expanded" with matches corresponding to the @@ -83,19 +78,16 @@ class Dispatcher (val ruleIndex: RuleIndex) { fun expand(activated: Occurrence): DispatchingFront = DispatchingFront(this, ruleIndex.forOccurrenceWithMask(activated) .map { (rule, mask) -> - if (!occId2tags.contains(activated.identity)) { - occId2tags.put(activated.identity, arrayListOf()) - } - occId2tags[activated.identity].add(rule.uniqueTag()) - getOrCreateProbe(rule.uniqueTag()).expand(activated, mask) }) + occId2tags.computeIfAbsent(activated) { _ -> arrayListOf() }.add(rule) + getOrCreateProbe(rule).expand(activated, mask) }) /** * Returns a [DispatchingFront] instance that is "contracted": all matches corresponding to the * specified discarded constraint occurrence are eliminated. */ fun contract(discarded: Occurrence): DispatchingFront = DispatchingFront(this, - occId2tags.remove(discarded.identity) - ?.mapNotNull { ruleTag -> ruletag2probe[ruleTag] } + occId2tags.remove(discarded) + ?.mapNotNull { ruleTag -> probeByRule[ruleTag] } ?.map { probe -> probe.contract(discarded) }) /** @@ -103,7 +95,7 @@ class Dispatcher (val ruleIndex: RuleIndex) { * be excluded from any further "match" set returned by [matches]. */ internal fun consume(consumedMatch: RuleMatchEx): DispatchingFront { - ruletag2probe[consumedMatch.rule().uniqueTag()]?.consume(consumedMatch) + probeByRule[consumedMatch.rule()]?.consume(consumedMatch) return DispatchingFront(this) } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleIndex.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleIndex.kt index 61dbfc91..63441125 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleIndex.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleIndex.kt @@ -17,7 +17,6 @@ package jetbrains.mps.logic.reactor.core import gnu.trove.TIntObjectHashMap -import gnu.trove.TObjectIntHashMap import jetbrains.mps.logic.reactor.evaluation.ConstraintOccurrence import jetbrains.mps.logic.reactor.logical.Logical import jetbrains.mps.logic.reactor.logical.MetaLogical @@ -29,16 +28,22 @@ import kotlin.collections.ArrayList import kotlin.collections.HashMap typealias RuleBits = BitSet + +typealias HeadBits = BitSet + fun emptyRuleBits() = BitSet() +fun emptyHeadBits() = BitSet() + + /** * A container for [Rule] instances with the ability to look up by [ConstraintOccurrence]. * * @author Fedor Isakov */ -class RuleIndex(rules: Iterable, profiler: Profiler? = null) : Iterable, RuleLookup +class RuleIndex(rules: Iterable, profiler: Profiler? = null) : RuleLookup { - private class IndexedRule(var idx: Int, val rule: Rule) + private class OrderedRule(var order: Int, val rule: Rule) // Terminology: // ruleBit - rule's index in the rules list @@ -49,13 +54,9 @@ class RuleIndex(rules: Iterable, profiler: Profiler? = null) : Iterable() - private val tag2bit = TObjectIntHashMap() - var nextBit: Int = 0 - private val bit2ruleAndMask = TIntObjectHashMap>() - - private val allRules = LinkedList() + private val bit2ruleAndMask = TIntObjectHashMap>() init { profiler.profile("build rule index") { @@ -70,23 +71,23 @@ class RuleIndex(rules: Iterable, profiler: Profiler? = null) : Iterable { val (ruleBits, slotMasks) = symbol2index[occ.constraint().symbol()]?.select(occ) ?: return emptyList() - val result = ArrayList() + val result = ArrayList() val itr = ruleBits.iterator() while (itr.hasNext()) { bit2ruleAndMask[itr.next()]?.let{ result.add(it.first) } } - result.sortBy { it.idx } + result.sortBy { it.order } return result.map { it.rule } } /** - * Returns a pair of rule and bit mask with 1's marking matching slots in constraint's head. + * Returns a pair of rule and bit mask with 1's marking matching slots in rule's head. */ fun forOccurrenceWithMask(occ: ConstraintOccurrence): Iterable> { val (ruleBits, argSlotMasks) = symbol2index[occ.constraint().symbol()]?.select(occ) ?: return emptyList() - val result = ArrayList>() + val result = ArrayList>() val itr = ruleBits.iterator() while (itr.hasNext()) { val ruleBit = itr.next() @@ -98,21 +99,17 @@ class RuleIndex(rules: Iterable, profiler: Profiler? = null) : Iterable = allRules.map { it.rule }.iterator() - fun buildIndexFromRules(rules: Iterable) { rules.forEachIndexed { idx, rule -> - val irule = IndexedRule(idx, rule) - addRuleToIndex(irule) - allRules.add(irule) + addRuleToIndex(OrderedRule(idx, rule)) } } - private fun addRuleToIndex(irule: IndexedRule) { + private fun addRuleToIndex(irule: OrderedRule) { val uniqueTag = irule.rule.uniqueTag() if (tag2rule.containsKey(uniqueTag)) throw IllegalStateException("duplicate rule tag $uniqueTag") val head = irule.rule.headKept() + irule.rule.headReplaced() @@ -123,7 +120,6 @@ class RuleIndex(rules: Iterable, profiler: Profiler? = null) : Iterable, profiler: Profiler? = null) : Iterable, profiler: Profiler? = null) : Iterable> { + fun select(occ: ConstraintOccurrence): Pair> { if (occ.constraint().symbol() != symbol) throw IllegalArgumentException() // by default select all rules where this constraint is in the head @@ -264,11 +262,11 @@ class RuleIndex(rules: Iterable, profiler: Profiler? = null) : Iterable() + val slotMasks = HashMap() for ((p, votes) in slotVotes.entries) { val (ruleBit, headPos) = p if (!votes.isEmpty || !wildcardSlots.isEmpty) { - slotMasks.getOrPut(ruleBit) { BitSet() }.set(headPos) + slotMasks.getOrPut(ruleBit) { emptyHeadBits() }.set(headPos) } } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt index 6eaff3c5..c5558e66 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleMatcher.kt @@ -38,13 +38,9 @@ interface RuleMatcher { fun probe(): RuleMatchingProbe - fun setRuleLookup(ruleLookup: RuleLookup) - - fun resetRuleLookup() - } -fun createRuleMatcher(lookup: RuleLookup, tag: Any): RuleMatcher = ReteRuleMatcherImpl(lookup, tag) +fun createRuleMatcher(rule: Rule): RuleMatcher = ReteRuleMatcherImpl(rule) // Trove stuff typealias Signature = TIntList diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt index 408f8327..d3cfd8f5 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ReteRuleMatcherImpl.kt @@ -44,21 +44,20 @@ fun Signature.toTrail() = TIntHashSet(this) fun signatureIndexOf() = TIntObjectHashMap>() -internal class ReteRuleMatcherImpl(private var ruleLookup: RuleLookup?, - private val tag: Any) : RuleMatcher +internal class ReteRuleMatcherImpl(private val rule: Rule) : RuleMatcher { val head = (lookupRule().headKept() + lookupRule().headReplaced()).toList() val propagation = lookupRule().headReplaced().count() == 0 - fun lookupRule(): Rule = ruleLookup?.lookupRuleByTag(tag) ?: throw IllegalStateException("can't lookup rule by tag: '${tag}'") + fun lookupRule(): Rule = rule override fun rule() = lookupRule() - override fun setRuleLookup(ruleLookup: RuleLookup) { this.ruleLookup = ruleLookup } - - override fun resetRuleLookup() { this.ruleLookup = null } +// override fun setRuleLookup(ruleLookup: RuleLookup) { this.ruleLookup = ruleLookup } +// +// override fun resetRuleLookup() { this.ruleLookup = null } override fun newProbe(): RuleMatchingProbe = ReteNetwork(head.size).also { probe = it } diff --git a/reactor/Test/test/RulesHelper.kt b/reactor/Test/test/RulesHelper.kt index 320ccd44..df5d2b94 100644 --- a/reactor/Test/test/RulesHelper.kt +++ b/reactor/Test/test/RulesHelper.kt @@ -28,7 +28,7 @@ class Builder(var rulesList: List) : RuleLookup { override fun lookupRuleByTag(tag: Any): Rule? = tag2rule[tag] - fun ruleMatcher(): RuleMatcher = createRuleMatcher(this, rules.first().uniqueTag()) + fun ruleMatcher(): RuleMatcher = createRuleMatcher(rules.first()) fun program(name: String): Program = programBuilder.program(name, rulesList)