Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Map;
import java.util.Set;

import eu.knowledge.engine.reasoner.BaseRule.CombiMatch;
import eu.knowledge.engine.reasoner.api.TripleVarBindingSet;
import eu.knowledge.engine.reasoner.rulenode.RuleNode;

Expand All @@ -12,10 +13,14 @@
*/
public interface AntSide {

public void setAntecedentCombiMatches(Set<CombiMatch> someCombiMatches);

public Set<CombiMatch> getAntecedentCombiMatches();

public void addAntecedentNeighbour(RuleNode neighbour, Set<Match> matches);

public Map<RuleNode, Set<Match>> getAntecedentNeighbours();

public boolean addResultBindingSetInput(RuleNode aNeighbor, TripleVarBindingSet bs);
public boolean addResultBindingSetInput(RuleNode aNeighbor, Map<Match, TripleVarBindingSet> someBindingSets);

}
25 changes: 16 additions & 9 deletions reasoner/src/main/java/eu/knowledge/engine/reasoner/BaseRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ public CompletableFuture<Void> handle(BindingSet aBindingSet) {
return null;
}
});
Map<BaseRule, Set<Match>> matches = getMatches(this, new HashSet<>(Arrays.asList(r)), false, aMatchConfig);
Set<CombiMatch> combiMatches = getMatches(this, new HashSet<>(Arrays.asList(r)), false, aMatchConfig);

Map<BaseRule, Set<Match>> matches = convertToMap(combiMatches);

if (matches.containsKey(r))
return matches.get(r);
Expand All @@ -194,7 +196,8 @@ public CompletableFuture<Void> handle(BindingSet aBindingSet) {
public Set<Match> antecedentMatches(Set<TriplePattern> aConsequent, EnumSet<MatchFlag> aMatchConfig) {
if (!this.antecedent.isEmpty()) {
Rule r = new Rule(new HashSet<>(), aConsequent);
Map<BaseRule, Set<Match>> matches = getMatches(this, new HashSet<>(Arrays.asList(r)), true, aMatchConfig);
Set<CombiMatch> combiMatches = getMatches(this, new HashSet<>(Arrays.asList(r)), true, aMatchConfig);
Map<BaseRule, Set<Match>> matches = convertToMap(combiMatches);
if (matches.containsKey(r))
return matches.get(r);
}
Expand Down Expand Up @@ -388,7 +391,7 @@ public static Map<TriplePattern, Set<CombiMatch>> getMatchesPerTriplePerRule(Set
* the target rule
* @return A set of matches that all contribute to some full matche.
*/
public static Map<BaseRule, Set<Match>> getMatches(BaseRule aTargetRule, Set<BaseRule> someCandidateRules,
public static Set<CombiMatch> getMatches(BaseRule aTargetRule, Set<BaseRule> someCandidateRules,
Comment thread
bnouwt marked this conversation as resolved.
boolean antecedentOfTarget, EnumSet<MatchFlag> config) {

Set<TriplePattern> targetGP = antecedentOfTarget ? aTargetRule.getAntecedent() : aTargetRule.getConsequent();
Expand All @@ -409,7 +412,7 @@ public static Map<BaseRule, Set<Match>> getMatches(BaseRule aTargetRule, Set<Bas
// a full match.
if (targetGP.isEmpty() || (config.contains(MatchFlag.FULLY_COVERED)
&& combiMatchesPerTriple.keySet().size() < targetGP.size()))
return new HashMap<>();
return new HashSet<>();

printCombiMatchesPerTriple(aTargetRule, combiMatchesPerTriple);

Expand Down Expand Up @@ -526,7 +529,7 @@ public static Map<BaseRule, Set<Match>> getMatches(BaseRule aTargetRule, Set<Bas

// printAllMatches(allMatches);

return convertToMap(allMatches);
return new HashSet<CombiMatch>(allMatches);
}

private static void printAllMatches(List<CombiMatch> allMatches) {
Expand Down Expand Up @@ -597,7 +600,7 @@ private static CombiMatch mergeCombiMatches(CombiMatch candidateCombiMatch, Comb
CombiMatch newCombiMatch = new CombiMatch(aBiggestCombiMatch);
Set<Match> newBiggestMatch = new HashSet<>(biggestMatch);

// we merge it with one of the avaialble matches (does that work?)
// we merge it with one of the available matches (does that work?)
for (Match m : biggestMatch) {
newMatch = m.merge(candidateMatch);
if (newMatch != null) {
Expand Down Expand Up @@ -635,7 +638,7 @@ private static boolean doesSameCandidateTripleMapToDifferentTriple(Match candida
for (Match biggestMatch : biggestMatches) {
var biggestMatchMP = biggestMatch.getMatchingPatterns();
for (Map.Entry<TriplePattern, TriplePattern> entry : biggestMatchMP.entrySet()) {
if (entry.getValue().equals(candidateMatchMP.getValue())) {
if (!entry.getValue().equals(candidateMatchMP.getValue())) {
Comment thread
bnouwt marked this conversation as resolved.
return true;
}
}
Expand All @@ -644,7 +647,7 @@ private static boolean doesSameCandidateTripleMapToDifferentTriple(Match candida
return false;
}

private static Map<BaseRule, Set<Match>> convertToMap(List<CombiMatch> combiMatches) {
private static Map<BaseRule, Set<Match>> convertToMap(Set<CombiMatch> combiMatches) {
Map<BaseRule, Set<Match>> matchesPerRule = new HashMap<>();
for (CombiMatch combiMatch : combiMatches) {
for (Map.Entry<BaseRule, Set<Match>> ruleMatch : combiMatch.entrySet()) {
Expand All @@ -670,13 +673,17 @@ private static Map<BaseRule, Set<Match>> convertToMap(List<CombiMatch> combiMatc
* matched to the same triple pattern. This is the case in transitivity
* scenario's and we there support multiple match objects.
*/
private static class CombiMatch extends HashMap<BaseRule, Set<Match>> {
public static class CombiMatch extends HashMap<BaseRule, Set<Match>> {
private static final long serialVersionUID = 1L;

public CombiMatch() {
super();
}

public CombiMatch(Map<BaseRule, Set<Match>> someRules) {
super(someRules);
}

/**
* @param aMatch a combi match object to check whether it is a sub combi match
* of this combi match.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Map;
import java.util.Set;

import eu.knowledge.engine.reasoner.BaseRule.CombiMatch;
import eu.knowledge.engine.reasoner.api.TripleVarBindingSet;
import eu.knowledge.engine.reasoner.rulenode.RuleNode;

Expand All @@ -12,9 +13,13 @@
*/
public interface ConsSide {

public void setConsequentCombiMatches(Set<CombiMatch> someMatches);

public Set<CombiMatch> getConsequentCombiMatches();

public void addConsequentNeighbour(RuleNode neighbour, Set<Match> matches);

public Map<RuleNode, Set<Match>> getConsequentNeighbours();
public boolean addFilterBindingSetInput(RuleNode aNeighbor, TripleVarBindingSet bs);

public boolean addFilterBindingSetInput(RuleNode aNeighbor, Map<Match, TripleVarBindingSet> someBindingSets);
}
172 changes: 94 additions & 78 deletions reasoner/src/main/java/eu/knowledge/engine/reasoner/ReasonerPlan.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
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;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.knowledge.engine.reasoner.BaseRule.CombiMatch;
import eu.knowledge.engine.reasoner.BaseRule.MatchFlag;
import eu.knowledge.engine.reasoner.api.Binding;
import eu.knowledge.engine.reasoner.api.BindingSet;
Expand Down Expand Up @@ -57,6 +59,97 @@ public ReasonerPlan(RuleStore aStore, ProactiveRule aStartRule, EnumSet<MatchFla
createOrGetReasonerNode(this.start, null);
}

private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) {

final RuleNode currentRuleNode;
if (this.ruleToRuleNode.containsKey(aRule))
return this.ruleToRuleNode.get(aRule);
else {
currentRuleNode = this.newNode(aRule);
}

// build the reasoner node graph
this.ruleToRuleNode.put(aRule, currentRuleNode);

if (isBackward()) {
// for now we only are interested in antecedent neighbors.
// TODO for looping we DO want to consider consequent neighbors as well.
Comment thread
bnouwt marked this conversation as resolved.

this.store.getAntecedentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> {
if (!(rule instanceof ProactiveRule)) {
Comment thread
bnouwt marked this conversation as resolved.
assert currentRuleNode instanceof AntSide;
var newNode = createOrGetReasonerNode(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);
Comment thread
bnouwt marked this conversation as resolved.
}
});

// store the combi matches when there are any antecedents.
if (!currentRuleNode.getRule().getAntecedent().isEmpty())
((AntSide) currentRuleNode)
.setAntecedentCombiMatches(this.store.getAntecedentCombiMatches(currentRuleNode.getRule()));
} else {
// interested in both consequent and antecedent neighbors

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);

var inverseMatches = Match.invertAll(matches);
((AntSide) newNode).addAntecedentNeighbour(currentRuleNode, inverseMatches);
} else {
LOG.trace("Skipped proactive rule: {}", rule);
Comment thread
bnouwt marked this conversation as resolved.
}
});

// store the combi matches when there are any antecedents.
if (!currentRuleNode.getRule().getConsequent().isEmpty())
((ConsSide) currentRuleNode)
.setConsequentCombiMatches(this.store.getConsequentCombiMatches(currentRuleNode.getRule()));

// antecedent neighbors to propagate bindings further via backward chaining

// determine whether our parent matches us partially
boolean ourAntecedentFullyMatchesParentConsequent = false;

Map<BaseRule, Set<Match>> antecedentNeighbors = this.store.getAntecedentNeighbors(aRule, this.matchConfig);
if (aParent != null && antecedentNeighbors.containsKey(aParent)) {
ourAntecedentFullyMatchesParentConsequent = antecedentFullyMatchesConsequent(aRule, aParent,
antecedentNeighbors.get(aParent));
}

if (!ourAntecedentFullyMatchesParentConsequent) {

antecedentNeighbors.forEach((rule, matches) -> {
if (!(rule instanceof ProactiveRule)) {
assert currentRuleNode instanceof AntSide;
var newNode = createOrGetReasonerNode(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);
}
});

if (!currentRuleNode.getRule().getAntecedent().isEmpty())
((AntSide) currentRuleNode)
.setAntecedentCombiMatches(this.store.getAntecedentCombiMatches(currentRuleNode.getRule()));
}
}

return currentRuleNode;
}

/**
* 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
Expand Down Expand Up @@ -132,6 +225,7 @@ public TaskBoard execute(BindingSet bindingSet) {
((AntSide) current).getAntecedentNeighbours().forEach((n, matches) -> {
var translated = toBeFilterPropagated.translate(n.getRule().getConsequent(),
Match.invertAll(matches));

boolean itChanged = ((ConsSide) n).addFilterBindingSetInput(current, translated);
if (itChanged) {
changed.add(n);
Expand Down Expand Up @@ -216,84 +310,6 @@ public boolean isBackward() {
return !this.start.getAntecedent().isEmpty() && this.start.getConsequent().isEmpty();
}

private RuleNode createOrGetReasonerNode(BaseRule aRule, BaseRule aParent) {

final RuleNode reasonerNode;
if (this.ruleToRuleNode.containsKey(aRule))
return this.ruleToRuleNode.get(aRule);
else {
reasonerNode = this.newNode(aRule);
}

// build the reasoner node graph
this.ruleToRuleNode.put(aRule, reasonerNode);

if (isBackward()) {
// for now we only are interested in antecedent neighbors.
// TODO for looping we DO want to consider consequent neighbors as well.

this.store.getAntecedentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> {
if (!(rule instanceof ProactiveRule)) {
assert reasonerNode instanceof AntSide;
var newNode = createOrGetReasonerNode(rule, aRule);
assert newNode instanceof ConsSide;
((AntSide) reasonerNode).addAntecedentNeighbour(newNode, matches);

var inverseMatches = Match.invertAll(matches);
// TODO: Validate with Barry if we can use the same `matches` object here
((ConsSide) newNode).addConsequentNeighbour(reasonerNode, inverseMatches);
} else {
LOG.trace("Skipped proactive rule: {}", rule);
}
});
} else {
// interested in both consequent and antecedent neighbors
this.store.getConsequentNeighbors(aRule, this.matchConfig).forEach((rule, matches) -> {
if (!(rule instanceof ProactiveRule)) {
assert reasonerNode instanceof ConsSide;
var newNode = createOrGetReasonerNode(rule, aRule);
((ConsSide) reasonerNode).addConsequentNeighbour(newNode, matches);

var inverseMatches = Match.invertAll(matches);
// TODO: Validate with Barry if we can use the same `matches` object here
((AntSide) newNode).addAntecedentNeighbour(reasonerNode, inverseMatches);
} else {
LOG.trace("Skipped proactive rule: {}", rule);
}
});

// antecedent neighbors to propagate bindings further via backward chaining

// determine whether our parent matches us partially
boolean ourAntecedentFullyMatchesParentConsequent = false;

Map<BaseRule, Set<Match>> antecedentNeighbors = this.store.getAntecedentNeighbors(aRule, this.matchConfig);
if (aParent != null && antecedentNeighbors.containsKey(aParent)) {
ourAntecedentFullyMatchesParentConsequent = antecedentFullyMatchesConsequent(aRule, aParent,
antecedentNeighbors.get(aParent));
}

if (!ourAntecedentFullyMatchesParentConsequent) {
antecedentNeighbors.forEach((rule, matches) -> {
if (!(rule instanceof ProactiveRule)) {
assert reasonerNode instanceof AntSide;
var newNode = createOrGetReasonerNode(rule, aRule);
assert newNode instanceof ConsSide;
((AntSide) reasonerNode).addAntecedentNeighbour(newNode, matches);

// TODO: Validate with Barry if we can use the same `matches` object here
var inverseMatches = Match.invertAll(matches);
((ConsSide) newNode).addConsequentNeighbour(reasonerNode, inverseMatches);
} else {
LOG.trace("Skipped proactive rule: {}", rule);
}
});
}
}

return reasonerNode;
}

private void scheduleOrDoTask(RuleNode current, TaskBoard taskBoard) {
if (this.useTaskBoard) {
taskBoard.addTask(current);
Expand Down
Loading