From 6cb6a2af38802c682c359ea9806b5d56e56ccf8c Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Tue, 19 Aug 2025 13:36:49 +0200 Subject: [PATCH 01/10] Small fixes that probably do not fix the overall problem. Next up: find out how we can get combi matches in the antecedent neighbors and make sure they are used. The current process adds them as consequent combi matches, but they are never used! --- .../engine/reasoner/rulenode/BindingSetStore.java | 10 ++++++++++ .../knowledge/engine/reasoner/rulestore/MatchNode.java | 2 +- .../knowledge/engine/reasoner/rulestore/RuleStore.java | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java index 812f27f93..ceaa76b1b 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/BindingSetStore.java @@ -10,6 +10,8 @@ import java.util.stream.Collectors; import org.apache.jena.graph.Node; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import eu.knowledge.engine.reasoner.BaseRule; import eu.knowledge.engine.reasoner.BaseRule.CombiMatch; @@ -32,6 +34,8 @@ public class BindingSetStore { private final Set neighbors; private final Map> neighborBindingSet = new HashMap<>(); + private static final Logger LOG = LoggerFactory.getLogger(BindingSetStore.class); + /** * This combi matches set need to be initialized after the * constructor has been called. @@ -104,7 +108,12 @@ private TripleVarBindingSet translateWithCombiMatches(Set aGraphP Set someCombiMatches, Map> someNeighborBS) { var combinedTVBS = new TripleVarBindingSet(aGraphPattern); + int i = 0; + int size = someCombiMatches.size(); for (CombiMatch cMatch : someCombiMatches) { + i = i + 1; + LOG.trace("Creating binding set for combi match: {}/{}", i, size); + // keep separate binding set per combi match var cMatchTVBS = new TripleVarBindingSet(aGraphPattern); @@ -160,6 +169,7 @@ public TripleVarBindingSet get() { if (this.combiMatches != null) this.cache = this.translateWithCombiMatches(this.graphPattern, this.combiMatches, this.neighborBindingSet); else { + LOG.trace("Ignoring combi matches for binding set construction."); TripleVarBindingSet combinedBS = new TripleVarBindingSet(graphPattern); for (TripleVarBindingSet bs : this.neighborBindingSet.values().stream().map(x -> x.values()) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java index e1002f634..ecaa40850 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java @@ -100,7 +100,7 @@ public void setAntecedentNeighbor(BaseRule aRule, Set someMatches) { * @param someCombiMatches The combi matches for this node on the consequent * side. */ - public void setConsequentMatches(Set someCombiMatches) { + public void setConsequentCombiMatches(Set someCombiMatches) { this.consequentCombiMatches = someCombiMatches; } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java index ca02f18f4..d1541685d 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java @@ -167,9 +167,11 @@ public Map> getConsequentNeighbors(BaseRule aRule, EnumSet< Set combiMatches = BaseRule.getMatches(aRule, this.getRules(), false, aConfig); // store combi matches - Map> newMapping = convertToMapping(combiMatches); + aMatchNode.setConsequentCombiMatches(combiMatches); // store normal matches + Map> newMapping = convertToMapping(combiMatches); + for (Map.Entry> entry : newMapping.entrySet()) { aMatchNode.setConsequentNeighbor(entry.getKey(), Match.invertAll(entry.getValue())); this.ruleToMatchNode.get(entry.getKey()).setAntecedentNeighbor(aRule, entry.getValue()); From c92626678e4b8916c7f5abd37ff3ad4a47bc64f4 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Mon, 25 Aug 2025 11:24:58 +0200 Subject: [PATCH 02/10] First try at making forward reasoning use combi matches. --- .../engine/reasoner/ReasonerPlan.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index efc26ac66..e18a732c7 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -94,12 +93,20 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { } else { // interested in both consequent and antecedent neighbors +// EnumSet modMatchConfig = EnumSet.copyOf(this.matchConfig); +// modMatchConfig.add(MatchFlag.SINGLE_RULE); + this.store.getConsequentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof ConsSide; var newNode = createOrGetReasonerNode(rule, aRule); ((ConsSide) currentRuleNode).addConsequentNeighbour(newNode, matches); + Set antCombiMatches = filterAndInvertCombiMatches(rule, aRule, + this.store.getConsequentCombiMatches(currentRuleNode.getRule())); + + ((AntSide) newNode).setAntecedentCombiMatches(antCombiMatches); + var inverseMatches = Match.invertAll(matches); ((AntSide) newNode).addAntecedentNeighbour(currentRuleNode, inverseMatches); } else { @@ -148,6 +155,29 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { return currentRuleNode; } + private Set filterAndInvertCombiMatches(BaseRule antRule, BaseRule consRule, + Set consequentCombiMatches) { + + Set filteredAndInvertedCombiMatches = new HashSet(); + + CombiMatch newCm; + for (CombiMatch cm : consequentCombiMatches) { + if (cm.containsKey(antRule)) { + newCm = new CombiMatch(); + filteredAndInvertedCombiMatches.add(newCm); + Set matches = cm.get(antRule); + Set newMatches = new HashSet(); + for (Match m : matches) { + newMatches.add(m.inverse()); + } + newCm.put(consRule, newMatches); + filteredAndInvertedCombiMatches.add(newCm); + } + } + + return filteredAndInvertedCombiMatches; + } + /** * Enable (default) or disable the {@link TaskBoard}. When it is disabled, all * tasks will be executed as they occur in the algorithm, and an EMPTY task From 084eb7b3e2afc3450130d7f698fea23aa29b33d8 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Tue, 26 Aug 2025 16:55:00 +0200 Subject: [PATCH 03/10] Trying to make combi matches work with forward reasoning. Unfortunately, many of the forward reasoning tests do no longer work, so we need to figure out which change caused this and whether we should revert the changes or modify them such that everything starts working again. --- .../engine/reasoner/ReasonerPlan.java | 17 +- .../reasoner/rulenode/FullRuleNode.java | 11 +- .../api/NotDesignedToWorkTogetherTest2.java | 154 ++++++++++++++++++ 3 files changed, 167 insertions(+), 15 deletions(-) create mode 100644 smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index e18a732c7..2eb98c662 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -93,8 +93,8 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { } else { // interested in both consequent and antecedent neighbors -// EnumSet modMatchConfig = EnumSet.copyOf(this.matchConfig); -// modMatchConfig.add(MatchFlag.SINGLE_RULE); + EnumSet modMatchConfig = EnumSet.copyOf(this.matchConfig); + modMatchConfig.add(MatchFlag.SINGLE_RULE); this.store.getConsequentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { @@ -164,14 +164,19 @@ private Set filterAndInvertCombiMatches(BaseRule antRule, BaseRule c for (CombiMatch cm : consequentCombiMatches) { if (cm.containsKey(antRule)) { newCm = new CombiMatch(); - filteredAndInvertedCombiMatches.add(newCm); Set matches = cm.get(antRule); Set newMatches = new HashSet(); for (Match m : matches) { - newMatches.add(m.inverse()); + + if (m.getMatchingPatterns().size() > 0 + && m.getMatchingPatterns().size() == antRule.getAntecedent().size()) { + newMatches.add(m.inverse()); + } + } + if (!newMatches.isEmpty()) { + newCm.put(consRule, newMatches); + filteredAndInvertedCombiMatches.add(newCm); } - newCm.put(consRule, newMatches); - filteredAndInvertedCombiMatches.add(newCm); } } diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/FullRuleNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/FullRuleNode.java index a19ac6501..a98340a42 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/FullRuleNode.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/FullRuleNode.java @@ -177,15 +177,8 @@ public void transformFilterBS() { @Override public boolean readyForApplyRule() { boolean isReady; - // TODO: This (the "Except" part) was needed to make transitivity work, but not - // sure if it is correct - - if (!this.resultBindingSetInput.get().isEmpty()) { - Set exceptNodes = this.getAllSameLoopNeighbors(); - isReady = this.resultBindingSetInput.haveAllNeighborsContributedExcept(exceptNodes); - } else { - isReady = false; - } + Set exceptNodes = this.getAllSameLoopNeighbors(); + isReady = this.resultBindingSetInput.haveAllNeighborsContributedExcept(exceptNodes); return isReady; } diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java new file mode 100644 index 000000000..f4bafb036 --- /dev/null +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java @@ -0,0 +1,154 @@ +package eu.knowledge.engine.smartconnector.api; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.apache.jena.shared.PrefixMapping; +import org.apache.jena.sparql.graph.PrefixMappingMem; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.knowledge.engine.reasoner.Rule; +import eu.knowledge.engine.reasoner.api.TriplePattern; +import eu.knowledge.engine.smartconnector.util.KnowledgeNetwork; +import eu.knowledge.engine.smartconnector.util.KnowledgeBaseImpl; + +/** + * This test tries to illustrate forward compatibility. We instantiate an + * App KB and a Lamp1 KB that exchange data about the on/off state of the lamp. + * When a new Lamp2 KB is introduced that does not support on/off because it is + * dimmable, we should how the reasoner+domain knowledge combination is able to + * make the app work with the new dimmable type of lamp although it was not + * designed to work with those types. + * + * This second versino of this unit test is meant to test specific behaviour of + * the reasoner where a full domain rule does is not activated, but there is + * still enough data to apply its consequent neighbor. + * + * @author nouwtb + * + */ +public class NotDesignedToWorkTogetherTest2 { + + private static final Logger LOG = LoggerFactory.getLogger(NotDesignedToWorkTogetherTest2.class); + + private static KnowledgeNetwork kn = new KnowledgeNetwork(); + private KnowledgeBaseImpl appKb = new KnowledgeBaseImpl("AppKB"); + private KnowledgeBaseImpl lamp1Kb = new KnowledgeBaseImpl("Lamp1KB"); + private KnowledgeBaseImpl lamp2Kb = new KnowledgeBaseImpl("Lamp2KB"); + private PrefixMapping prefixes = new PrefixMappingMem().setNsPrefix("ex", "http://example.org/") + .setNsPrefix("time", "https://www.w3.org/TR/owl-time/") + .setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + + @Test + public void test() throws InterruptedException { + + kn.addKB(appKb); + kn.addKB(lamp1Kb); + kn.addKB(lamp2Kb); + + final CountDownLatch latch = new CountDownLatch(2); + + GraphPattern lampGP = new GraphPattern(prefixes, "?l rdf:type ex:OnOffLamp .", "?l ex:isOn ?o ."); + PostKnowledgeInteraction appKbPost = new PostKnowledgeInteraction(new CommunicativeAct(), lampGP, null); + appKb.register(appKbPost); + + HashSet rule1ant = new HashSet<>(Arrays.asList( + new TriplePattern( + "?s "), + new TriplePattern( + "?s \"true\"^^"))); + HashSet rule1con = new HashSet<>(Arrays.asList( + new TriplePattern( + "?s "), + new TriplePattern("?s \"100\""))); + + // to test whether the reasoner of this example still works, we slightly modify + // a domain rule where it does not produce a binding set. This should not cause + // this unit test to fail, because the other domain rule is all we need. + HashSet rule2ant = new HashSet<>(Arrays.asList( + new TriplePattern( + " "), + new TriplePattern( + " \"false\"^^"))); + HashSet rule2con = new HashSet<>(Arrays.asList( + new TriplePattern( + " "), + new TriplePattern(" \"0\""))); + + Rule rule1 = new Rule(rule1ant, rule1con); + Rule rule2 = new Rule(rule2ant, rule2con); + appKb.setDomainKnowledge(new HashSet<>(Arrays.asList(rule1, rule2))); + + ReactKnowledgeInteraction lamp1KbReact = new ReactKnowledgeInteraction(new CommunicativeAct(), lampGP, null); + lamp1Kb.register(lamp1KbReact, (ReactHandler) (aKI, aReactInfo) -> { + + Iterator iterator = aReactInfo.getArgumentBindings().iterator(); + while (iterator.hasNext()) { + Binding b = iterator.next(); + if (b.containsKey("l") && b.get("l").equals("")) { + LOG.info("Turned lamp1 '{}'", b.get("o")); + latch.countDown(); + } + } + return new BindingSet(); + }); + + GraphPattern lamp2GP = new GraphPattern(prefixes, "?l rdf:type .", + "?l ?b ."); + ReactKnowledgeInteraction lamp2KbReact = new ReactKnowledgeInteraction(new CommunicativeAct(), lamp2GP, null); + lamp2Kb.register(lamp2KbReact, (ReactHandler) (aKI, aReactInfo) -> { + + Iterator iterator = aReactInfo.getArgumentBindings().iterator(); + while (iterator.hasNext()) { + Binding b = iterator.next(); + if (b.containsKey("l") && b.get("l").equals("")) { + LOG.info("Turned lamp2 '{}'", b.get("b")); + latch.countDown(); + } + } + + return new BindingSet(); + }); + + kn.sync(); + + BindingSet argument = new BindingSet(); + Binding binding = new Binding(); + binding.put("l", ""); + binding.put("o", "\"true\"^^"); + argument.add(binding); + Binding binding2 = new Binding(); + binding2.put("l", ""); + binding2.put("o", "\"true\"^^"); + argument.add(binding2); + PostPlan pp = appKb.planPost(appKbPost, new RecipientSelector()); + + pp.getReasonerPlan().getStore().printGraphVizCode(pp.getReasonerPlan()); + pp.execute(argument); + + boolean allTouched = latch.await(3600000, TimeUnit.MILLISECONDS); + + assertTrue(allTouched); + + } + + @AfterAll + public static void close() { + LOG.info("Clean up: {}", NotDesignedToWorkTogetherTest2.class.getSimpleName()); + try { + kn.stop().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Stopping the Knowledge Network should succeed: {}", e); + } + } + +} From aed0c15e9e2e2f873b7a82c4120144ebba56280b Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Tue, 26 Aug 2025 17:07:09 +0200 Subject: [PATCH 04/10] Improved the combi match propagation when forward reasoning. --- .../java/eu/knowledge/engine/reasoner/ReasonerPlan.java | 7 ++++++- .../smartconnector/api/NotDesignedToWorkTogetherTest2.java | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index 2eb98c662..f4a89c5ef 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -105,7 +105,12 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { Set antCombiMatches = filterAndInvertCombiMatches(rule, aRule, this.store.getConsequentCombiMatches(currentRuleNode.getRule())); - ((AntSide) newNode).setAntecedentCombiMatches(antCombiMatches); + var existing = ((AntSide) newNode).getAntecedentCombiMatches(); + + if (existing == null) + ((AntSide) newNode).setAntecedentCombiMatches(antCombiMatches); + else + existing.addAll(antCombiMatches); var inverseMatches = Match.invertAll(matches); ((AntSide) newNode).addAntecedentNeighbour(currentRuleNode, inverseMatches); diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java index f4bafb036..9a68be38a 100644 --- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java @@ -135,7 +135,7 @@ public void test() throws InterruptedException { pp.getReasonerPlan().getStore().printGraphVizCode(pp.getReasonerPlan()); pp.execute(argument); - boolean allTouched = latch.await(3600000, TimeUnit.MILLISECONDS); + boolean allTouched = latch.await(3000, TimeUnit.MILLISECONDS); assertTrue(allTouched); From dc40b8cb9358aa37bf39a9881960fcdaede9e30c Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Tue, 26 Aug 2025 18:08:10 +0200 Subject: [PATCH 05/10] Improve naming of method. --- .../eu/knowledge/engine/reasoner/ReasonerPlan.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index f4a89c5ef..4bd7f806f 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -47,7 +47,7 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule) { this.store = aStore; this.start = aStartRule; this.ruleToRuleNode = new HashMap<>(); - createOrGetReasonerNode(this.start, null); + createOrGetRuleNode(this.start, null); } public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet aConfig) { @@ -55,10 +55,10 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet(); this.matchConfig = aConfig; - createOrGetReasonerNode(this.start, null); + createOrGetRuleNode(this.start, null); } - private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { + private RuleNode createOrGetRuleNode(BaseRule aRule, BaseRule aParent) { final RuleNode currentRuleNode; if (this.ruleToRuleNode.containsKey(aRule)) @@ -75,7 +75,7 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { this.store.getAntecedentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof AntSide; - var newNode = createOrGetReasonerNode(rule, aRule); + var newNode = createOrGetRuleNode(rule, aRule); assert newNode instanceof ConsSide; ((AntSide) currentRuleNode).addAntecedentNeighbour(newNode, matches); @@ -99,7 +99,7 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { this.store.getConsequentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof ConsSide; - var newNode = createOrGetReasonerNode(rule, aRule); + var newNode = createOrGetRuleNode(rule, aRule); ((ConsSide) currentRuleNode).addConsequentNeighbour(newNode, matches); Set antCombiMatches = filterAndInvertCombiMatches(rule, aRule, @@ -140,7 +140,7 @@ private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) { antecedentNeighbors.forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof AntSide; - var newNode = createOrGetReasonerNode(rule, aRule); + var newNode = createOrGetRuleNode(rule, aRule); assert newNode instanceof ConsSide; ((AntSide) currentRuleNode).addAntecedentNeighbour(newNode, matches); From ba27a798b8f7fbf5657ecc2620726b137de28767 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Wed, 24 Sep 2025 13:24:54 +0200 Subject: [PATCH 06/10] Intermediate commit with only one unit test failing. --- .../engine/reasoner/ReasonerPlan.java | 113 +++++++++++++----- .../engine/reasoner/rulestore/RuleStore.java | 73 ++++++----- .../engine/reasoner/ForwardTest.java | 65 ++++------ 3 files changed, 150 insertions(+), 101 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index 4bd7f806f..db0c411b5 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -1,12 +1,16 @@ package eu.knowledge.engine.reasoner; import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Comparator; import java.util.Deque; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; @@ -47,7 +51,7 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule) { this.store = aStore; this.start = aStartRule; this.ruleToRuleNode = new HashMap<>(); - createOrGetRuleNode(this.start, null); + createOrGetRuleNode(this.start); } public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet aConfig) { @@ -55,10 +59,10 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet(); this.matchConfig = aConfig; - createOrGetRuleNode(this.start, null); + createOrGetRuleNode(this.start); } - private RuleNode createOrGetRuleNode(BaseRule aRule, BaseRule aParent) { + private RuleNode createOrGetRuleNode(BaseRule aRule) { final RuleNode currentRuleNode; if (this.ruleToRuleNode.containsKey(aRule)) @@ -75,14 +79,14 @@ private RuleNode createOrGetRuleNode(BaseRule aRule, BaseRule aParent) { this.store.getAntecedentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof AntSide; - var newNode = createOrGetRuleNode(rule, aRule); + var newNode = createOrGetRuleNode(rule); assert newNode instanceof ConsSide; ((AntSide) currentRuleNode).addAntecedentNeighbour(newNode, matches); var inverseMatches = Match.invertAll(matches); ((ConsSide) newNode).addConsequentNeighbour(currentRuleNode, inverseMatches); } else { - LOG.trace("Skipped proactive rule: {}", rule); + LOG.trace("Skipped proactive rule1: {}", rule); } }); @@ -96,10 +100,13 @@ private RuleNode createOrGetRuleNode(BaseRule aRule, BaseRule aParent) { EnumSet modMatchConfig = EnumSet.copyOf(this.matchConfig); modMatchConfig.add(MatchFlag.SINGLE_RULE); - this.store.getConsequentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> { + Map> consequentNeighbors = this.store.getConsequentNeighbors(aRule, this.matchConfig); + + LOG.info("Rule1: {} ({})", aRule, consequentNeighbors.size()); + consequentNeighbors.forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof ConsSide; - var newNode = createOrGetRuleNode(rule, aRule); + var newNode = createOrGetRuleNode(rule); ((ConsSide) currentRuleNode).addConsequentNeighbour(newNode, matches); Set antCombiMatches = filterAndInvertCombiMatches(rule, aRule, @@ -115,51 +122,93 @@ private RuleNode createOrGetRuleNode(BaseRule aRule, BaseRule aParent) { var inverseMatches = Match.invertAll(matches); ((AntSide) newNode).addAntecedentNeighbour(currentRuleNode, inverseMatches); } else { - LOG.trace("Skipped proactive rule: {}", rule); + LOG.trace("Skipped proactive rule2: {}", rule); } }); - // store the combi matches when there are any antecedents. - if (!currentRuleNode.getRule().getConsequent().isEmpty()) - ((ConsSide) currentRuleNode) - .setConsequentCombiMatches(this.store.getConsequentCombiMatches(currentRuleNode.getRule())); + // store the combi matches when there are any consequents. + if (!currentRuleNode.getRule().getConsequent().isEmpty()) { + Set existing = ((ConsSide) currentRuleNode).getConsequentCombiMatches(); + Set consequentCombiMatches = this.store + .getConsequentCombiMatches(currentRuleNode.getRule()); + if (existing == null) { + ((ConsSide) currentRuleNode).setConsequentCombiMatches(consequentCombiMatches); + } else + existing.addAll(consequentCombiMatches); + } // antecedent neighbors to propagate bindings further via backward chaining // determine whether our parent matches us partially - boolean ourAntecedentFullyMatchesParentConsequent = false; + boolean ourAntecedentFullyMatchesParentConsequent = true; Map> antecedentNeighbors = this.store.getAntecedentNeighbors(aRule, this.matchConfig); - if (aParent != null && antecedentNeighbors.containsKey(aParent)) { - ourAntecedentFullyMatchesParentConsequent = antecedentFullyMatchesConsequent(aRule, aParent, - antecedentNeighbors.get(aParent)); + for (BaseRule neighborRule : antecedentNeighbors.keySet()) { + if (this.isAncestorOfStartNode(neighborRule)) { + ourAntecedentFullyMatchesParentConsequent &= antecedentFullyMatchesConsequent(aRule, neighborRule, + antecedentNeighbors.get(neighborRule)); + } } if (!ourAntecedentFullyMatchesParentConsequent) { - antecedentNeighbors.forEach((rule, matches) -> { - if (!(rule instanceof ProactiveRule)) { - assert currentRuleNode instanceof AntSide; - var newNode = createOrGetRuleNode(rule, aRule); - assert newNode instanceof ConsSide; - ((AntSide) currentRuleNode).addAntecedentNeighbour(newNode, matches); - - var inverseMatches = Match.invertAll(matches); - ((ConsSide) newNode).addConsequentNeighbour(currentRuleNode, inverseMatches); - } else { - LOG.trace("Skipped proactive rule: {}", rule); - } + assert currentRuleNode instanceof AntSide; + var newNode = createOrGetRuleNode(rule); + assert newNode instanceof ConsSide; + ((AntSide) currentRuleNode).addAntecedentNeighbour(newNode, matches); + + var inverseMatches = Match.invertAll(matches); + ((ConsSide) newNode).addConsequentNeighbour(currentRuleNode, inverseMatches); }); - if (!currentRuleNode.getRule().getAntecedent().isEmpty()) - ((AntSide) currentRuleNode) - .setAntecedentCombiMatches(this.store.getAntecedentCombiMatches(currentRuleNode.getRule())); + if (!currentRuleNode.getRule().getAntecedent().isEmpty()) { + var existing = ((AntSide) currentRuleNode).getAntecedentCombiMatches(); + Set antecedentCombiMatches = this.store + .getAntecedentCombiMatches(currentRuleNode.getRule()); + if (existing == null) { + ((AntSide) currentRuleNode).setAntecedentCombiMatches(antecedentCombiMatches); + } else + existing.addAll(antecedentCombiMatches); + } } } return currentRuleNode; } + private boolean isAncestorOfStartNode(BaseRule aRule) { + return isAncestorOfStartNode(aRule, new ArrayList()); + } + + /** + * Check whether the given BaseRule is an ancestor of the start node of this + * reasoning plan. + * + * @param aRule The rule to check whether it is an ancestor. + * @return {@code true} when {@code aRule} is an ancestor, {@code false} + * otherwise. + */ + private boolean isAncestorOfStartNode(BaseRule aRule, List visited) { + + if (visited.contains(aRule)) + return false; + + visited.add(aRule); + + boolean isAncestor = false; + + if (this.getStartNode().getRule().equals(aRule)) { + isAncestor = true; + } else { + Map> antecedentNeighbors = this.store.getAntecedentNeighbors(aRule); + + for (BaseRule antecedentNeighbor : antecedentNeighbors.keySet()) { + isAncestor |= isAncestorOfStartNode(antecedentNeighbor, visited); + } + } + return isAncestor; + } + private Set filterAndInvertCombiMatches(BaseRule antRule, BaseRule consRule, Set consequentCombiMatches) { @@ -279,6 +328,8 @@ 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(); diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java index d1541685d..18a6b2094 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java @@ -205,19 +205,19 @@ public void printGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) { public String getGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) { String color = "red"; - String width = "2"; + String width = "1.5"; StringBuilder sb = new StringBuilder(); sb.append("strict digraph {\n"); - Map ruleToName = new HashMap<>(); + Map ruleToId = new HashMap<>(); for (MatchNode r : ruleToMatchNode.values()) { - String currentName = ruleToName.get(r.getRule()); - if (currentName == null) { - currentName = /* "rule" + ruleNumber; */ generateName(r.getRule()); - assert !currentName.isEmpty(); + String currentId = ruleToId.get(r.getRule()); + if (currentId == null) { + currentId = Integer.toHexString(System.identityHashCode(r)); + assert !currentId.isEmpty(); String replaceAll = toStringRule(r.getRule()).replaceAll("\\\"", "\\\\\""); // check the colouring @@ -229,28 +229,30 @@ public String getGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) { } } - String shape = "shape=\"circle\""; + String shape = "shape=\"rect\""; + String doubleShape = ""; if (r.getRule() instanceof ProactiveRule) { - shape = "shape=\"doublecircle\""; + doubleShape = ", peripheries=2"; } - sb.append(currentName).append("[").append(shape).append(pen).append("tooltip=").append("\"") - .append(replaceAll).append("\"").append("]").append("\n"); - ruleToName.put(r.getRule(), currentName); + sb.append(q(currentId)).append("[").append(shape).append(", ").append(pen).append("tooltip=") + .append("\"").append(replaceAll).append("\"").append(doubleShape).append(", label=") + .append(generateName(r.getRule())).append("]").append("\n"); + ruleToId.put(r.getRule(), Integer.toHexString(System.identityHashCode(r))); } Map> antecedentNeighbors = r.getAntecedentNeighbors(); Set anteNeigh = antecedentNeighbors.keySet(); - String neighName; + String neighId; for (BaseRule neighR : anteNeigh) { - neighName = ruleToName.get(neighR); + neighId = ruleToId.get(neighR); - if (neighName == null) { - neighName = /* "rule" + ruleNumber; */ generateName(neighR); - assert !neighName.isEmpty(); - String replaceAll = toStringRule(neighR).replaceAll("\\\"", "\\\\\""); + if (neighId == null) { + neighId = Integer.toHexString(System.identityHashCode(neighR)); + assert !neighId.isEmpty(); + String ruleString = toStringRule(neighR).replaceAll("\\\"", "\\\\\""); // check the colouring String pen = ""; @@ -261,15 +263,17 @@ public String getGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) { } } - String shape = "shape=\"circle\""; + String shape = "shape=\"rect\""; + String doubleShape = ""; if (neighR instanceof ProactiveRule) { - shape = "shape=\"doublecircle\""; + doubleShape = ", peripheries=2"; } - sb.append(neighName).append("[").append(shape).append(pen).append("tooltip=").append("\"") - .append(replaceAll).append("\"").append("]").append("\n"); + sb.append(q(neighId)).append("[").append(shape).append(pen).append("tooltip=").append("\"") + .append(ruleString).append("\"").append(doubleShape).append(", label=") + .append(generateName(neighR)).append("").append("]").append("\n"); - ruleToName.put(neighR, neighName); + ruleToId.put(neighR, neighId); } String pen = ""; @@ -282,7 +286,7 @@ public String getGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) { int nrOfMatches = antecedentNeighbors.get(neighR).size(); - sb.append(neighName).append(BaseRule.ARROW).append(currentName).append("[label=").append(nrOfMatches) + sb.append(q(neighId)).append("->").append(q(currentId)).append("[label=").append(nrOfMatches) .append(" ").append(pen).append("]").append("\n"); } @@ -295,8 +299,12 @@ public String getGraphVizCode(ReasonerPlan aPlan, boolean urlOnly) { + (urlOnly ? "" : "\n" + sb.toString()); } + private String q(String aString) { + return "\"" + aString + "\""; + } + private String toStringRule(BaseRule neighR) { - return neighR.getAntecedent() + " -> " + neighR.getConsequent(); + return neighR.getAntecedent() + " → " + neighR.getConsequent(); } private String trimAtLength(String aString, int aLength) { @@ -344,15 +352,17 @@ private String generateName(BaseRule r) { String name = r.getName(); MessageDigest digest; - byte[] encodedhash = new byte[0]; + String encodedhash = "unknown"; try { digest = MessageDigest.getInstance("SHA-256"); - encodedhash = digest.digest(name.getBytes(StandardCharsets.UTF_8)); + +// encodedhash = digest.digest(name.getBytes(StandardCharsets.UTF_8)); + encodedhash = Integer.toHexString(System.identityHashCode(r)); } catch (NoSuchAlgorithmException e) { LOG.error("{}", e); } - - return "\"" + bytesToHex(encodedhash) + "\\n" + antecedent + "->\\n" + consequent + "\""; + // bytesToHex(...) + return "\"" + antecedent + "→\\n" + consequent + "\""; } private static String bytesToHex(byte[] hash) { @@ -422,4 +432,11 @@ private String uriToString(URI uri) { return text; } + public void findAllMatches() { + for (Map.Entry entry : this.ruleToMatchNode.entrySet()) { + this.getConsequentNeighbors(entry.getKey(), EnumSet.noneOf(MatchFlag.class)); + this.getAntecedentNeighbors(entry.getKey(), EnumSet.noneOf(MatchFlag.class)); + } + } + } diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java index dc1044893..4c01327a0 100644 --- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java +++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java @@ -74,15 +74,13 @@ public void init() { // data rule DataBindingSetHandler aBindingSetHandler = new DataBindingSetHandler(new Table(new String[] { // @formatter:off - "a", "b", "n" - // @formatter:on + "a", "b", "n" + // @formatter:on }, new String[] { // @formatter:off - ",,\"Barry\"", - ",,\"Janny\"", - ",,\"Fenna\"", - ",,\"Benno\"", - // @formatter:on + ",,\"Barry\"", ",,\"Janny\"", ",,\"Fenna\"", + ",,\"Benno\"", + // @formatter:on })); optionalRule = new Rule(new HashSet<>(), @@ -154,10 +152,7 @@ public void test() throws InterruptedException, ExecutionException { // @formatter:on }, new String[] { // @formatter:off - ",", - ",", - ",", - ",", + ",", ",", ",", ",", // @formatter:on }).getData()); @@ -207,8 +202,7 @@ public CompletableFuture handle(BindingSet bs) { // @formatter:on }, new String[] { // @formatter:off - ",", - ",", + ",", ",", // @formatter:on }).getData()); @@ -250,10 +244,7 @@ public void testMultipleLeafs() throws InterruptedException, ExecutionException // @formatter:on }, new String[] { // @formatter:off - ",", - ",", - ",", - ",", + ",", ",", ",", ",", // @formatter:on }).getData()); @@ -299,10 +290,7 @@ public void testBackwardChainingDuringForwardChaining() throws InterruptedExcept // @formatter:on }, new String[] { // @formatter:off - ",", - ",", - ",", - ",", + ",", ",", ",", ",", // @formatter:on }).getData()); @@ -344,17 +332,17 @@ public void testNoBackwardChainingDuringForwardChainingIfFullMatch() new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "v" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off - ",4", - ",5", - ",6" - // @formatter:on + ",4", ",5", ",6" + // @formatter:on })))); ReasonerPlan rn = new ReasonerPlan(store, aStartRule); + store.findAllMatches(); + store.printGraphVizCode(rn); LOG.info("\n{}", rn); @@ -403,13 +391,11 @@ public void testBackwardChainingDuringForwardChainingIfPartialMatch() new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "r" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off - ",", - ",", - "," - // @formatter:on + ",", ",", "," + // @formatter:on })))); ProactiveRule aStartRule = new ProactiveRule(new HashSet<>(), premise); @@ -462,13 +448,11 @@ public void testBackwardChainingDuringForwardChainingIfPartialWithTwoStages() new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "r" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off - ",", - ",", - "," - // @formatter:on + ",", ",", "," + // @formatter:on })))); ProactiveRule aStartRule = new ProactiveRule(new HashSet<>(), premise); @@ -540,13 +524,13 @@ public void testAlternativeForFullMatch() throws InterruptedException, Execution new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "a" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off ",", - ",", + ",", "," - // @formatter:on + // @formatter:on })))); TriplePattern tp41 = new TriplePattern("?s ?b"); @@ -558,7 +542,6 @@ public void testAlternativeForFullMatch() throws InterruptedException, Execution store.printGraphVizCode(rn); - LOG.info("\n{}", rn); BindingSet bs = new BindingSet(); bs.addAll(new Table(new String[] { // @formatter:off @@ -575,8 +558,6 @@ public void testAlternativeForFullMatch() throws InterruptedException, Execution tb.executeScheduledTasks().get(); } - LOG.info("\n{}", rn); - LOG.info("BindingSet: {}", aBindingSetHandler1.getBindingSet()); assertFalse(aBindingSetHandler1.getBindingSet().isEmpty()); From 700ffb07f74061e24a71071dd62d5e41c3bebf4c Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Wed, 24 Sep 2025 13:53:38 +0200 Subject: [PATCH 07/10] Fixed final unit test. Next remove all unnecessary logs, etc. --- .../eu/knowledge/engine/reasoner/ReasonerPlan.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index db0c411b5..739880e00 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -140,17 +140,23 @@ private RuleNode createOrGetRuleNode(BaseRule aRule) { // antecedent neighbors to propagate bindings further via backward chaining // determine whether our parent matches us partially - boolean ourAntecedentFullyMatchesParentConsequent = true; + boolean ourAntecedentFullyMatchesAllParentConsequents = false; + boolean allMatch = true; + int count = 0; Map> antecedentNeighbors = this.store.getAntecedentNeighbors(aRule, this.matchConfig); for (BaseRule neighborRule : antecedentNeighbors.keySet()) { if (this.isAncestorOfStartNode(neighborRule)) { - ourAntecedentFullyMatchesParentConsequent &= antecedentFullyMatchesConsequent(aRule, neighborRule, + allMatch &= antecedentFullyMatchesConsequent(aRule, neighborRule, antecedentNeighbors.get(neighborRule)); + count++; } } - if (!ourAntecedentFullyMatchesParentConsequent) { + if (count > 0 && allMatch) + ourAntecedentFullyMatchesAllParentConsequents = true; + + if (!ourAntecedentFullyMatchesAllParentConsequents) { antecedentNeighbors.forEach((rule, matches) -> { assert currentRuleNode instanceof AntSide; var newNode = createOrGetRuleNode(rule); From 082c76f0e9363421aec6048642172d15ad5d1ba6 Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Wed, 24 Sep 2025 18:03:22 +0200 Subject: [PATCH 08/10] Clean up the code and add javadocs to be ready for merging. --- .../engine/reasoner/ReasonerPlan.java | 46 +++++++++++++++++-- .../engine/reasoner/rulestore/RuleStore.java | 7 --- .../engine/reasoner/ForwardTest.java | 2 +- .../api/NotDesignedToWorkTogetherTest2.java | 4 +- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java index 739880e00..8c356ac92 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java @@ -2,7 +2,6 @@ import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Comparator; import java.util.Deque; import java.util.EnumSet; import java.util.HashMap; @@ -10,7 +9,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; @@ -47,6 +45,9 @@ public class ReasonerPlan { private EnumSet matchConfig = EnumSet.noneOf(MatchFlag.class); private boolean useTaskBoard = true; + /** + * @see ReasonerPlan#ReasonerPlan(RuleStore, ProactiveRule, EnumSet) + */ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule) { this.store = aStore; this.start = aStartRule; @@ -54,6 +55,16 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule) { createOrGetRuleNode(this.start); } + /** + * Create a new reasoner plan with the given {@link RuleStore}, + * {@link ProactiveRule} and {@link MatchFlag}s. + * + * @param aStore The store into which all the rules are available to use for + * the plan. + * @param aStartRule The Proactive rule (should be available in {@code aStore}) + * to start the plan with. + * @param aConfig The configuration to use for creating the plan. + */ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet aConfig) { this.store = aStore; this.start = aStartRule; @@ -62,6 +73,14 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet { @@ -102,7 +123,6 @@ private RuleNode createOrGetRuleNode(BaseRule aRule) { Map> consequentNeighbors = this.store.getConsequentNeighbors(aRule, this.matchConfig); - LOG.info("Rule1: {} ({})", aRule, consequentNeighbors.size()); consequentNeighbors.forEach((rule, matches) -> { if (!(rule instanceof ProactiveRule)) { assert currentRuleNode instanceof ConsSide; @@ -182,6 +202,14 @@ private RuleNode createOrGetRuleNode(BaseRule aRule) { return currentRuleNode; } + /** + * Checks if the given rule is an ancestor of the Proactive start node of this + * reasoner plan. With ancestor we mean whether starting from the proactive node + * we can reach the given node following arrows in the same direction. + * + * @param aRule The rule to check. + * @return Whether the given rule is an ancestor. + */ private boolean isAncestorOfStartNode(BaseRule aRule) { return isAncestorOfStartNode(aRule, new ArrayList()); } @@ -215,6 +243,18 @@ private boolean isAncestorOfStartNode(BaseRule aRule, List visited) { return isAncestor; } + /** + * Filters and inverts the given set of combi matches that connect the given + * {@code antRule} and {@code consRule}. + * + * @param antRule The antecedent rule for which the given combi + * matches were created. + * @param consRule The consequent rule for which the given combi + * matches are being inversed. + * @param consequentCombiMatches The combi matches to filter and invert. + * @return Only those combimatches that contain antRule and contain the same + * triple patterns as the antecedent of antRule. + */ private Set filterAndInvertCombiMatches(BaseRule antRule, BaseRule consRule, Set consequentCombiMatches) { diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java index 18a6b2094..483465ac7 100644 --- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java +++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java @@ -432,11 +432,4 @@ private String uriToString(URI uri) { return text; } - public void findAllMatches() { - for (Map.Entry entry : this.ruleToMatchNode.entrySet()) { - this.getConsequentNeighbors(entry.getKey(), EnumSet.noneOf(MatchFlag.class)); - this.getAntecedentNeighbors(entry.getKey(), EnumSet.noneOf(MatchFlag.class)); - } - } - } diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java index 4c01327a0..8cbd88dde 100644 --- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java +++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java @@ -341,7 +341,7 @@ public void testNoBackwardChainingDuringForwardChainingIfFullMatch() ReasonerPlan rn = new ReasonerPlan(store, aStartRule); - store.findAllMatches(); +// store.findAllMatches(); store.printGraphVizCode(rn); diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java index 9a68be38a..a235f5dd3 100644 --- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/NotDesignedToWorkTogetherTest2.java @@ -29,8 +29,8 @@ * make the app work with the new dimmable type of lamp although it was not * designed to work with those types. * - * This second versino of this unit test is meant to test specific behaviour of - * the reasoner where a full domain rule does is not activated, but there is + * This second version of this unit test is meant to test specific behaviour of + * the reasoner where a full domain rule does is not get activated, but there is * still enough data to apply its consequent neighbor. * * @author nouwtb From a782534404903b9670c24aea1216d12d1517e80f Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Wed, 24 Sep 2025 18:07:17 +0200 Subject: [PATCH 09/10] Fix formatting of some code. --- .../engine/reasoner/ForwardTest.java | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java index 8cbd88dde..dc1044893 100644 --- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java +++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/ForwardTest.java @@ -74,13 +74,15 @@ public void init() { // data rule DataBindingSetHandler aBindingSetHandler = new DataBindingSetHandler(new Table(new String[] { // @formatter:off - "a", "b", "n" - // @formatter:on + "a", "b", "n" + // @formatter:on }, new String[] { // @formatter:off - ",,\"Barry\"", ",,\"Janny\"", ",,\"Fenna\"", - ",,\"Benno\"", - // @formatter:on + ",,\"Barry\"", + ",,\"Janny\"", + ",,\"Fenna\"", + ",,\"Benno\"", + // @formatter:on })); optionalRule = new Rule(new HashSet<>(), @@ -152,7 +154,10 @@ public void test() throws InterruptedException, ExecutionException { // @formatter:on }, new String[] { // @formatter:off - ",", ",", ",", ",", + ",", + ",", + ",", + ",", // @formatter:on }).getData()); @@ -202,7 +207,8 @@ public CompletableFuture handle(BindingSet bs) { // @formatter:on }, new String[] { // @formatter:off - ",", ",", + ",", + ",", // @formatter:on }).getData()); @@ -244,7 +250,10 @@ public void testMultipleLeafs() throws InterruptedException, ExecutionException // @formatter:on }, new String[] { // @formatter:off - ",", ",", ",", ",", + ",", + ",", + ",", + ",", // @formatter:on }).getData()); @@ -290,7 +299,10 @@ public void testBackwardChainingDuringForwardChaining() throws InterruptedExcept // @formatter:on }, new String[] { // @formatter:off - ",", ",", ",", ",", + ",", + ",", + ",", + ",", // @formatter:on }).getData()); @@ -332,17 +344,17 @@ public void testNoBackwardChainingDuringForwardChainingIfFullMatch() new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "v" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off - ",4", ",5", ",6" - // @formatter:on + ",4", + ",5", + ",6" + // @formatter:on })))); ReasonerPlan rn = new ReasonerPlan(store, aStartRule); -// store.findAllMatches(); - store.printGraphVizCode(rn); LOG.info("\n{}", rn); @@ -391,11 +403,13 @@ public void testBackwardChainingDuringForwardChainingIfPartialMatch() new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "r" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off - ",", ",", "," - // @formatter:on + ",", + ",", + "," + // @formatter:on })))); ProactiveRule aStartRule = new ProactiveRule(new HashSet<>(), premise); @@ -448,11 +462,13 @@ public void testBackwardChainingDuringForwardChainingIfPartialWithTwoStages() new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "r" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off - ",", ",", "," - // @formatter:on + ",", + ",", + "," + // @formatter:on })))); ProactiveRule aStartRule = new ProactiveRule(new HashSet<>(), premise); @@ -524,13 +540,13 @@ public void testAlternativeForFullMatch() throws InterruptedException, Execution new DataBindingSetHandler(new Table(new String[] { // @formatter:off "s", "a" - // @formatter:on + // @formatter:on }, new String[] { // @formatter:off ",", - ",", + ",", "," - // @formatter:on + // @formatter:on })))); TriplePattern tp41 = new TriplePattern("?s ?b"); @@ -542,6 +558,7 @@ public void testAlternativeForFullMatch() throws InterruptedException, Execution store.printGraphVizCode(rn); + LOG.info("\n{}", rn); BindingSet bs = new BindingSet(); bs.addAll(new Table(new String[] { // @formatter:off @@ -558,6 +575,8 @@ public void testAlternativeForFullMatch() throws InterruptedException, Execution tb.executeScheduledTasks().get(); } + LOG.info("\n{}", rn); + LOG.info("BindingSet: {}", aBindingSetHandler1.getBindingSet()); assertFalse(aBindingSetHandler1.getBindingSet().isEmpty()); From 4918f8b72503dbb65f1d643cd6a72a82da89e33e Mon Sep 17 00:00:00 2001 From: Barry Nouwt Date: Wed, 24 Sep 2025 18:24:30 +0200 Subject: [PATCH 10/10] Remove unused imports. --- .../eu/knowledge/engine/reasoner/JenaRDFSRulesTest.java | 1 - .../java/eu/knowledge/engine/reasoner/PruningTest.java | 5 ----- .../knowledge/engine/reasoner/api/ReasoningPlanTest.java | 7 +------ .../knowledge/engine/rest/api/TestAskWithGapsEnabled.java | 5 ----- .../engine/rest/api/TestAskWithGapsNotEnabled.java | 4 ---- .../eu/knowledge/engine/rest/api/TestDomainKnowledge.java | 3 --- .../engine/rest/api/TestRegisterKnowledgeInteraction.java | 1 - 7 files changed, 1 insertion(+), 25 deletions(-) diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaRDFSRulesTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaRDFSRulesTest.java index 59d6c22c0..3e32f53c0 100644 --- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaRDFSRulesTest.java +++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaRDFSRulesTest.java @@ -20,7 +20,6 @@ import org.apache.jena.rdf.model.StmtIterator; import org.apache.jena.sparql.lang.arq.ParseException; import org.apache.jena.vocabulary.RDF; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/PruningTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/PruningTest.java index f2259047c..b37103fa1 100644 --- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/PruningTest.java +++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/PruningTest.java @@ -16,11 +16,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import eu.knowledge.engine.reasoner.ProactiveRule; -import eu.knowledge.engine.reasoner.ReasonerPlan; -import eu.knowledge.engine.reasoner.Rule; -import eu.knowledge.engine.reasoner.SinkBindingSetHandler; -import eu.knowledge.engine.reasoner.TaskBoard; import eu.knowledge.engine.reasoner.api.Binding; import eu.knowledge.engine.reasoner.api.BindingSet; import eu.knowledge.engine.reasoner.api.TriplePattern; diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/api/ReasoningPlanTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/api/ReasoningPlanTest.java index 21cff1cf2..701849cda 100644 --- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/api/ReasoningPlanTest.java +++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/api/ReasoningPlanTest.java @@ -8,7 +8,6 @@ import java.util.Set; import java.util.concurrent.ExecutionException; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import eu.knowledge.engine.reasoner.BaseRule; @@ -16,9 +15,6 @@ import eu.knowledge.engine.reasoner.ReasonerPlan; import eu.knowledge.engine.reasoner.Rule; import eu.knowledge.engine.reasoner.TaskBoard; -import eu.knowledge.engine.reasoner.api.Binding; -import eu.knowledge.engine.reasoner.api.BindingSet; -import eu.knowledge.engine.reasoner.api.TriplePattern; import eu.knowledge.engine.reasoner.rulestore.RuleStore; import eu.knowledge.engine.reasoner.util.DataBindingSetHandler; import eu.knowledge.engine.reasoner.util.Table; @@ -74,10 +70,9 @@ public void test() throws IOException, InterruptedException, ExecutionException store.getConsequentNeighbors(r); } - store.printGraphVizCode(null); - ReasonerPlan plan = new ReasonerPlan(store, rule); + store.printGraphVizCode(plan); // plan.optimize(); BindingSet aBindingSet = new BindingSet(); diff --git a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsEnabled.java b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsEnabled.java index ddf1b83cc..14fee24f9 100644 --- a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsEnabled.java +++ b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsEnabled.java @@ -1,18 +1,13 @@ package eu.knowledge.engine.rest.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.io.IOException; -import java.net.MalformedURLException; import java.net.URL; import java.util.Map; -import org.apache.jena.atlas.logging.Log; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; diff --git a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsNotEnabled.java b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsNotEnabled.java index 8f4a29c04..a681da211 100644 --- a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsNotEnabled.java +++ b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestAskWithGapsNotEnabled.java @@ -2,17 +2,13 @@ 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.io.IOException; -import java.net.MalformedURLException; import java.net.URL; import java.util.Map; -import org.apache.jena.atlas.logging.Log; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; diff --git a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestDomainKnowledge.java b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestDomainKnowledge.java index e31354a76..f0c2d5c24 100644 --- a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestDomainKnowledge.java +++ b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestDomainKnowledge.java @@ -1,14 +1,11 @@ package eu.knowledge.engine.rest.api; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.net.URL; import java.util.Map; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; diff --git a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestRegisterKnowledgeInteraction.java b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestRegisterKnowledgeInteraction.java index ea135efc1..ba0b2c553 100644 --- a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestRegisterKnowledgeInteraction.java +++ b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestRegisterKnowledgeInteraction.java @@ -6,7 +6,6 @@ import java.net.URL; import java.util.Map; -import org.apache.jena.atlas.logging.Log; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled;