From 445108da74db8be3b17c8378c7cfed7f82f09afc Mon Sep 17 00:00:00 2001 From: Fedor Isakov Date: Tue, 8 Oct 2019 13:16:56 +0200 Subject: [PATCH] Fix RuleIndex returning too many matches for a constraint w/wildcard arg. --- .../mps/logic/reactor/core/RuleIndex.kt | 104 ++++++++---------- 1 file changed, 48 insertions(+), 56 deletions(-) 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 7940cd60..6f97a06c 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleIndex.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/RuleIndex.kt @@ -173,6 +173,8 @@ class RuleIndex(ruleLists: Iterable) : Iterable, RuleLookup { */ inner class ArgumentRuleIndex(val symbol: ConstraintSymbol) { + val symbolSelector = BitSet() + // value -> List of Pairs of rule bits and head positions val anySelectors = ArrayList>>>() @@ -180,8 +182,6 @@ class RuleIndex(ruleLists: Iterable) : Iterable, RuleLookup { val wildcardSelectors = ArrayList() - val noArgSelector = BitSet() - init { for (idx in 1..symbol.arity()) { anySelectors.add(HashMap()) @@ -191,24 +191,20 @@ class RuleIndex(ruleLists: Iterable) : Iterable, RuleLookup { } fun update(cst: Constraint, ruleBit: Int, headPos: Int) { - if (cst.arguments().isEmpty()) { - noArgSelector.set(ruleBit) - - } else { - for ((argIdx, arg) in cst.arguments().withIndex()) { - val value2indices = anySelectors[argIdx] - when (arg) { - is MetaLogical<*> -> - // all values should be accepted by a meta logical - wildcardSelectors[argIdx].set(ruleBit) - is Term -> - termSelectors.set(argIdx, termSelectors[argIdx].put(arg, ruleBit to headPos)) - is Any -> - value2indices.getOrPut(arg) { arrayListOf() }.add(ruleBit to headPos) - else -> - throw NullPointerException() // never happens + symbolSelector.set(ruleBit) + for ((argIdx, arg) in cst.arguments().withIndex()) { + val value2indices = anySelectors[argIdx] + when (arg) { + is MetaLogical<*> -> + // all values should be accepted by a meta logical + wildcardSelectors[argIdx].set(ruleBit) + is Term -> + termSelectors.set(argIdx, termSelectors[argIdx].put(arg, ruleBit to headPos)) + is Any -> + value2indices.getOrPut(arg) { arrayListOf() }.add(ruleBit to headPos) + else -> + throw NullPointerException() // never happens - } } } } @@ -219,48 +215,44 @@ class RuleIndex(ruleLists: Iterable) : Iterable, RuleLookup { fun select(occ: ConstraintOccurrence): Pair> { if (occ.constraint().symbol() != symbol) throw IllegalArgumentException() - // initially select all rules - val upToBit = rulesList.size - ruleBits.set(0, upToBit) + // initially select all rules where this constraint is in the head + ruleBits.clear() + ruleBits.or(symbolSelector) val slotVotes = HashMap, BitSet>() val commonVotes = BitSet() - if (occ.arguments().isEmpty()) { - ruleBits.and(noArgSelector) - - } else { - for ((argIdx, arg) in occ.arguments().withIndex()) { - val value2indices = anySelectors[argIdx] - val termIndices = termSelectors[argIdx] - val wildcardIndices = wildcardSelectors[argIdx] - if (arg is Logical<*> && !arg.isBound) { - // ALL values must be selected for a free logical - commonVotes.set(argIdx) - continue - } - - andRuleIndices.clear(0, upToBit) - andRuleIndices.or(wildcardIndices) - - val argVal = if (arg is Logical<*>) arg.findRoot().value() else arg - when (argVal) { - is Term -> - termIndices.lookupValues(argVal).forEach { (ruleBit, headPos) -> - andRuleIndices.set(ruleBit) - slotVotes.getOrPut(ruleBit to headPos) { BitSet() }.set(argIdx) - } - is Any -> - // ensure only rules with either matching values or wildcard arguments get selected - value2indices[argVal]?.run { forEach { (ruleBit, headPos) -> - andRuleIndices.set(ruleBit) - slotVotes.getOrPut(ruleBit to headPos) { BitSet() }.set(argIdx) - } } - } - ruleBits.and(andRuleIndices) - - if (ruleBits.isEmpty) break + for ((argIdx, arg) in occ.arguments().withIndex()) { + val value2indices = anySelectors[argIdx] + val termIndices = termSelectors[argIdx] + val wildcardIndices = wildcardSelectors[argIdx] + if (arg is Logical<*> && !arg.isBound) { + // ALL values must be selected for a free logical + commonVotes.set(argIdx) + continue } + + andRuleIndices.clear() + andRuleIndices.or(wildcardIndices) + + val argVal = if (arg is Logical<*>) arg.findRoot().value() else arg + when (argVal) { + is Term -> + termIndices.lookupValues(argVal).forEach { (ruleBit, headPos) -> + andRuleIndices.set(ruleBit) + slotVotes.getOrPut(ruleBit to headPos) { BitSet() }.set(argIdx) + } + is Any -> + // ensure only rules with either matching values or wildcard arguments get selected + value2indices[argVal]?.run { forEach { (ruleBit, headPos) -> + andRuleIndices.set(ruleBit) + slotVotes.getOrPut(ruleBit to headPos) { BitSet() }.set(argIdx) + } } + } + + ruleBits.and(andRuleIndices) + + if (ruleBits.isEmpty) break } val slotMasks = HashMap()