Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 53 additions & 11 deletions reasoner/src/main/java/eu/knowledge/engine/reasoner/BaseRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@ public static enum MatchFlag {
* Only look for the biggest combi matches and ignore combi matches that are a
* submatch of another combi match.
*/
ONLY_BIGGEST;
ONLY_BIGGEST,

/**
* Temp name: If the current combi match already has a triple pattern matched by
* one rule, this flag makes sure that a next triple pattern should always only
* be matched to that one rule if it exists in there and only if this one rule
* does not have the triple pattern will it allow other rules to match to that
* triple pattern.
*/
ONLY_NEW_RULE_WHEN_NECESSARY;

public static final EnumSet<MatchFlag> ALL_OPTS = EnumSet.allOf(MatchFlag.class);
}
Expand Down Expand Up @@ -422,6 +431,8 @@ public static Set<CombiMatch> getMatches(BaseRule aTargetRule, Set<BaseRule> som
List<CombiMatch> toBeAddedToBiggestMatches = null, toBeAddedToSmallerMatches = null;
Set<Integer> toBeDemotedMatchIndices = null;

Set<BaseRule> candidateRulesInBiggestMatch = new HashSet<>();

Iterator<Map.Entry<TriplePattern, Set<CombiMatch>>> triplePatternMatchesIter = combiMatchesPerTriple.entrySet()
.iterator();

Expand All @@ -430,6 +441,10 @@ public static Set<CombiMatch> getMatches(BaseRule aTargetRule, Set<BaseRule> som
LOG.trace("{}/{} ({}): biggest: {}, smaller: {} ({})", 1, combiMatchesPerTriple.size(), value.size(),
biggestMatches.size(), smallerMatches.size(), aConfig);
biggestMatches.addAll(value);

for (CombiMatch cm : biggestMatches) {
candidateRulesInBiggestMatch.addAll(cm.keySet());
}
}

int cnt = 1;
Expand All @@ -454,15 +469,37 @@ public static Set<CombiMatch> getMatches(BaseRule aTargetRule, Set<BaseRule> som
for (int i = 0; i < biggestMatches.size(); i++) {
CombiMatch aBiggestMatch = biggestMatches.get(i);
// compare/combine combimatches.
CombiMatch newCombiMatch = mergeCombiMatches(candidateCombiMatch, aBiggestMatch, aConfig);

if (newCombiMatch != null) {
// successful merge add new biggest and demote old biggest
toBeAddedToBiggestMatches.add(newCombiMatch);
candidateWasMerged = true;
toBeDemotedMatchIndices.add(i);
} else if (aConfig.contains(MatchFlag.FULLY_COVERED))
toBeDemotedMatchIndices.add(i);

boolean tryMerge = true;
// TODO: this does not seem to be going in the right direction, because this way
// the ordering of the triple patterns is important and we do not want that.
// TODO can we move this outside the current loops?
BaseRule candidateRule = candidateCombiMatch.keySet().iterator().next();
if (aConfig.contains(MatchFlag.ONLY_NEW_RULE_WHEN_NECESSARY)
&& !aBiggestMatch.containsKey(candidateRule) && candidateRulesInBiggestMatch.contains(candidateRule)) {
// check if a rule already present in aBiggestMatch
// can match the current triple pattern

for (CombiMatch cm : candidateCombiMatches) {
if (!cm.equals(candidateCombiMatch)) {
if (aBiggestMatch.containsKey(cm.keySet().iterator().next())) {
tryMerge = false;
}
}
}
}

if (tryMerge) {
CombiMatch newCombiMatch = mergeCombiMatches(candidateCombiMatch, aBiggestMatch, aConfig);

if (newCombiMatch != null) {
// successful merge add new biggest and demote old biggest
toBeAddedToBiggestMatches.add(newCombiMatch);
candidateWasMerged = true;
toBeDemotedMatchIndices.add(i);
} else if (aConfig.contains(MatchFlag.FULLY_COVERED))
toBeDemotedMatchIndices.add(i);
}
}

if (!aConfig.contains(MatchFlag.FULLY_COVERED)) {
Expand Down Expand Up @@ -516,6 +553,11 @@ public static Set<CombiMatch> getMatches(BaseRule aTargetRule, Set<BaseRule> som
// add all toBeAddedMatches
biggestMatches.addAll(toBeAddedToBiggestMatches);
smallerMatches.addAll(toBeAddedToSmallerMatches);

for(CombiMatch big: toBeAddedToBiggestMatches)
{
candidateRulesInBiggestMatch.addAll(big.keySet());
}
}

toBeAddedToBiggestMatches = null;
Expand Down Expand Up @@ -622,7 +664,7 @@ && doesSameCandidateTripleMapToDifferentTriple(candidateMatch, biggestMatch)) {
}

} else if (!config.contains(MatchFlag.SINGLE_RULE)) {
// rule not yet present, add new entry for rule.
// rule not yet present, add new entry for rule
CombiMatch newCombiMatch = new CombiMatch(aBiggestCombiMatch);
Set<Match> matches = new HashSet<>();
matches.add(candidateMatch);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,6 @@ public TaskBoard execute(BindingSet bindingSet) {
var translated = toBeResultPropagated.translate(n.getRule().getAntecedent(),
Match.invertAll(matches));

LOG.trace("EEK: {}", n);

TripleVarBindingSet beforeBindingSet = n.getResultBindingSetInput();
boolean itChanged = ((AntSide) n).addResultBindingSetInput(current, translated);
TripleVarBindingSet afterBindingSet = n.getResultBindingSetInput();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public EnumSet<MatchFlag> toConfig(boolean antecedentOfTarget) {
MatchFlag.FULLY_COVERED);
break;
case NORMAL_LEVEL:
config = EnumSet.of(MatchFlag.ONE_TO_ONE, MatchFlag.ONLY_BIGGEST);
config = EnumSet.of(MatchFlag.ONE_TO_ONE, MatchFlag.ONLY_BIGGEST, MatchFlag.ONLY_NEW_RULE_WHEN_NECESSARY);

// disable fully covered when matching consequents.
if (antecedentOfTarget)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package eu.knowledge.engine.smartconnector.api;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.util.Iterator;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import org.apache.jena.shared.PrefixMapping;
import org.apache.jena.sparql.graph.PrefixMappingMem;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.knowledge.engine.smartconnector.util.KnowledgeBaseImpl;
import eu.knowledge.engine.smartconnector.util.KnowledgeNetwork;

public class TestAskAnswer6 {

private static final int MAX_SECONDS = 10000;

private static final Logger LOG = LoggerFactory.getLogger(TestAskAnswer6.class);

private static KnowledgeBaseImpl kb1;
private static KnowledgeBaseImpl kb2;
private static KnowledgeBaseImpl kb3;
private static KnowledgeBaseImpl kb4;
private static KnowledgeBaseImpl kb5;
private static KnowledgeBaseImpl kb6;
private static KnowledgeBaseImpl kb7;
private static KnowledgeBaseImpl kb8;
private static KnowledgeBaseImpl kb9;

private PrefixMappingMem prefixes;

private String graphPattern1 = """
?a <https://www.tno.nl/example/b1> ?c1 .
?a <https://www.tno.nl/example/b2> ?c2 .
?a <https://www.tno.nl/example/b3> ?c3 .
?a <https://www.tno.nl/example/b4> ?c4 .
?a <https://www.tno.nl/example/b5> ?c5 .
?a <https://www.tno.nl/example/b6> ?c6 .
?a <https://www.tno.nl/example/b7> ?c7 .
?a <https://www.tno.nl/example/b8> ?c8 .
?a <https://www.tno.nl/example/b9> ?c9 .
""";

private String graphPattern2 = """
?a <https://www.tno.nl/example/b2> ?c2 .
?a <https://www.tno.nl/example/b3> ?c3 .
?a <https://www.tno.nl/example/b4> ?c4 .
?a <https://www.tno.nl/example/b5> ?c5 .
?a <https://www.tno.nl/example/b6> ?c6 .
?a <https://www.tno.nl/example/b7> ?c7 .
?a <https://www.tno.nl/example/b8> ?c8 .
?a <https://www.tno.nl/example/b9> ?c9 .
""";

private String graphPattern3 = """
?a <https://www.tno.nl/example/b1> ?c1 .
?a <https://www.tno.nl/example/b2> ?c2 .
?a <https://www.tno.nl/example/b3> ?c3 .
?a <https://www.tno.nl/example/b4> ?c4 .
?a <https://www.tno.nl/example/b5> ?c5 .
?a <https://www.tno.nl/example/b6> ?c6 .
?a <https://www.tno.nl/example/b7> ?c7 .
?a <https://www.tno.nl/example/b8> ?c8 .
""";

@BeforeAll
public static void setup() throws InterruptedException, BrokenBarrierException, TimeoutException {
}

@Test
public void testAskAnswer() throws InterruptedException {

prefixes = new PrefixMappingMem();
prefixes.setNsPrefixes(PrefixMapping.Standard);
prefixes.setNsPrefix("ex", "https://www.tno.nl/example/");

var kn = new KnowledgeNetwork();
kb1 = new KnowledgeBaseImpl("kb1");
kn.addKB(kb1);

kb1.setReasonerLevel(2);

kb2 = new KnowledgeBaseImpl("kb2");
kn.addKB(kb2);
kb3 = new KnowledgeBaseImpl("kb3");
kn.addKB(kb3);
kb4 = new KnowledgeBaseImpl("kb4");
kn.addKB(kb4);
kb5 = new KnowledgeBaseImpl("kb5");
kn.addKB(kb5);
kb6 = new KnowledgeBaseImpl("kb6");
kn.addKB(kb6);
kb7 = new KnowledgeBaseImpl("kb7");
kn.addKB(kb7);
kb8 = new KnowledgeBaseImpl("kb8");
kn.addKB(kb8);
kb9 = new KnowledgeBaseImpl("kb9");
kn.addKB(kb9);

GraphPattern gp = new GraphPattern(prefixes, this.graphPattern1);
AskKnowledgeInteraction askKI = new AskKnowledgeInteraction(new CommunicativeAct(), gp);
kb1.register(askKI);

createKI(kb2, this.graphPattern1);
createKI(kb3, this.graphPattern3);
createKI(kb4, this.graphPattern2);
createKI(kb5, this.graphPattern1);
createKI(kb6, this.graphPattern1);
createKI(kb7, this.graphPattern1);
createKI(kb8, this.graphPattern1);
createKI(kb9, this.graphPattern1);

kn.sync();

// start testing!
BindingSet bindings = null;
try {
LOG.info("Before ask.");
long start = System.currentTimeMillis();
AskResult result = kb1.ask(askKI, new BindingSet()).get();
long delta = System.currentTimeMillis() - start;
result.getReasonerPlan().getStore().printGraphVizCode(result.getReasonerPlan());
assertTrue(delta < MAX_SECONDS,
"It should take " + MAX_SECONDS + "ms maximum to finish this test, but was " + delta + "ms.");
LOG.info("After ask.");
bindings = result.getBindings();
} catch (InterruptedException | ExecutionException e) {
fail(e);
}

Iterator<Binding> iter = bindings.iterator();

assertFalse(iter.hasNext(), "there should be no bindings");
}

private void createKI(KnowledgeBaseImpl aKb, String aGraphPattern) {
GraphPattern gp1 = new GraphPattern(prefixes, aGraphPattern);
AnswerKnowledgeInteraction aKI = new AnswerKnowledgeInteraction(new CommunicativeAct(), gp1);
aKb.register(aKI, (AnswerHandler) (anAKI, anAnswerExchangeInfo) -> {
assertTrue(
anAnswerExchangeInfo.getIncomingBindings().isEmpty()
|| anAnswerExchangeInfo.getIncomingBindings().iterator().next().getVariables().isEmpty(),
"Should not have bindings in this binding set.");

// this test is about the graph pattern matching, so we can just return an empty
// binding.
BindingSet bindingSet = new BindingSet();

return bindingSet;
});
}

@AfterAll
public static void cleanup() {
LOG.info("Clean up: {}", TestAskAnswer6.class.getSimpleName());
cleanKB(kb1);
cleanKB(kb2);
cleanKB(kb3);
cleanKB(kb4);
cleanKB(kb5);
cleanKB(kb6);
cleanKB(kb7);
cleanKB(kb8);
cleanKB(kb9);

}

private static void cleanKB(KnowledgeBaseImpl aKb) {
if (aKb != null) {
aKb.stop();
} else {
fail("KB should not be null!");
}
}
}
Loading