fr.boreal.model.ruleCompilation.id.IDRuleCompilation Maven / Gradle / Ivy
The newest version!
package fr.boreal.model.ruleCompilation.id;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import fr.boreal.model.kb.api.RuleBase;
import fr.boreal.model.logicalElements.api.Atom;
import fr.boreal.model.logicalElements.api.Predicate;
import fr.boreal.model.logicalElements.api.Substitution;
import fr.boreal.model.logicalElements.api.Term;
import fr.boreal.model.logicalElements.factory.api.TermFactory;
import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
import fr.boreal.model.logicalElements.impl.AtomImpl;
import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
import fr.boreal.model.partition.TermPartition;
import fr.boreal.model.rule.api.FORule;
import fr.boreal.model.ruleCompilation.api.RuleCompilationResult;
import fr.boreal.model.ruleCompilation.api.RuleCompilation;
import fr.boreal.model.ruleCompilation.api.RuleCompilationCondition;
/**
* Version as implemented by Melanie in graal
* Compilation for atomic rules (head and body) with no existential variables or constants
*/
public class IDRuleCompilation implements RuleCompilation {
private final TermFactory tf = SameObjectTermFactory.instance();
// a matrix for store conditions ( p -> q : [q][p] )
private final Map>> conditions;
/**
* Create a new empty compilation
*/
public IDRuleCompilation() {
this.conditions = new HashMap<>();
}
@Override
public void compile(RuleBase rb) {
List compilable = this.extractCompilable(rb);
this.createIDCondition(compilable.iterator());
this.computeSaturation();
}
/**
*
* Creates a record with the partition of the compiled rules.
*
*/
@Override
public RuleCompilationResult compileAndGet(RuleBase rb) {
List snapshot_original_rulebase = new ArrayList<>(rb.getRules());
List compilable_rules = this.extractCompilable(rb);
List non_compilable_rules = new ArrayList<>(snapshot_original_rulebase);
non_compilable_rules.removeAll(compilable_rules);
this.createIDCondition(compilable_rules.iterator());
this.computeSaturation();
return new RuleCompilationResult(this,compilable_rules, compilable_rules, non_compilable_rules);
}
@Override
public boolean isMoreSpecificThan(Atom a, Atom b) {
Predicate predB = a.getPredicate();
Predicate predH = b.getPredicate();
List conditions = this.getConditions(predB, predH);
for (RuleCompilationCondition condition : conditions) {
if (condition.check(a, b)) {
return true;
}
}
return false;
}
@Override
public Set> unfold(Atom a) {
try {
HashSet> res = new HashSet<>();
res.add(new ImmutablePair<>(a, new SubstitutionImpl()));
Predicate predH = a.getPredicate();
Map> condH = this.conditions.get(predH);
if (condH != null) {
for (Map.Entry> entry : condH.entrySet()) {
Predicate predB = entry.getKey();
for (RuleCompilationCondition cond : entry.getValue()) {
Pair, Substitution> ret = cond.instantiate(List.of(a.getTerms()));
if (ret != null) {
List generatedBody = ret.getKey();
res.add(Pair.of(new AtomImpl(predB, generatedBody), ret.getValue()));
}
}
}
}
return res;}
catch(Exception e) {
return null;
}
}
@Override
public boolean isCompatible(Predicate p, Predicate q) {
if (p.equals(q))
return true;
else
return !getConditions(p, q).isEmpty();
}
@Override
public Set getCompatiblePredicates(Predicate p) {
Set res = new HashSet<>();
Map> condH = this.conditions.get(p);
res.add(p);
if (condH != null) {
res.addAll(condH.keySet());
}
return res;
}
@Override
public Set getHomomorphisms(Atom a, Atom b, Substitution s) {
Set res = new HashSet<>();
Predicate predB = b.getPredicate();
Predicate predH = a.getPredicate();
List conditions = this.getConditions(predB, predH);
for (RuleCompilationCondition condition : conditions) {
Substitution homo = condition.homomorphism(List.of(a.getTerms()), List.of(b.getTerms()), s);
if (homo != null) {
res.add(homo);
}
}
return res;
}
@Override
public Set getUnifications(Atom a, Atom b) {
Set res = new HashSet<>();
Predicate predB = a.getPredicate();
Predicate predH = b.getPredicate();
for (RuleCompilationCondition cond : this.getConditions(predB, predH)) {
TermPartition unifier = cond.unifier(a, b);
if (unifier != null) {
res.add(unifier);
}
}
return res;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for(Predicate q : this.conditions.keySet()) {
for(Predicate p : this.conditions.get(q).keySet()) {
for(RuleCompilationCondition c : this.conditions.get(q).get(p)) {
sb.append(p).append(" <= ").append(q).append(" with ").append(c).append("\n");
}
}
}
return sb.toString();
}
private boolean addCompilation(Atom a, Atom b) {
Predicate predBody = a.getPredicate();
Predicate predHead = b.getPredicate();
IDRuleCompilationCondition cond = new IDRuleCompilationCondition(a.getTerms(), b.getTerms());
Map> condH = this.conditions.computeIfAbsent(predHead, k -> new HashMap<>());
List conditions = condH.computeIfAbsent(predBody, k -> new ArrayList<>());
if (!conditions.contains(cond)) {
conditions.add(cond);
return true;
} else {
return false;
}
}
private List getConditions(Predicate predB, Predicate predH) {
List res = new ArrayList<>();
if (predB.equals(predH)) {
ArrayList terms = new ArrayList<>(predB.arity());
for (int i = 0; i < predH.arity(); i++) {
terms.add(this.tf.createOrGetFreshVariable());
}
res.add(new IDRuleCompilationCondition(terms, terms));
}
Map> condH = this.conditions.get(predH);
if (condH != null) {
List condB = condH.get(predB);
if(condB != null) {
res.addAll(condB);
}
}
return res;
}
/**
* Compute the saturation of this compilation
*/
private void computeSaturation() {
// deep copy of conditions
Map>> conditionsTmp = deepCopyMapMapList(this.conditions);
// p -> q
Predicate p, q;
for (Map.Entry>> e : conditionsTmp.entrySet()) {
q = e.getKey();
for (Map.Entry> map : e.getValue().entrySet()) {
p = map.getKey();
for (RuleCompilationCondition conditionPQ : map.getValue()) {
computeSaturation(conditionsTmp, p, q, conditionPQ);
}
}
}
}
private void computeSaturation(
Map>> conditionsTmp,
Predicate p, Predicate q,
RuleCompilationCondition conditionPQ) {
Map> map = conditionsTmp.get(p);
if (map != null) {
for (Map.Entry> e : map.entrySet()) {
Predicate r = e.getKey();
for (RuleCompilationCondition conditionRP : e.getValue()) {
RuleCompilationCondition conditionRQ = conditionRP.composeWith(conditionPQ);
if (conditionRQ != null) {
// filter trivial implication - p(x,y,z) -> p(x,y,z)
if (!(r.equals(q) && conditionRQ.isIdentity())) {
if (addCondition(r, q, conditionRQ)) {
this.computeSaturation(conditionsTmp, r, q,
conditionRQ);
}
}
}
}
}
}
}
private static Map>> deepCopyMapMapList(
Map>> map) {
Map>> tmp = new HashMap<>();
for (Map.Entry>> e : map.entrySet()) {
tmp.put(e.getKey(), deepCopyMapList(e.getValue()));
}
return tmp;
}
private static Map> deepCopyMapList(
Map> map) {
Map> tmp = new HashMap<>();
for (Map.Entry> e : map.entrySet()) {
tmp.put(e.getKey(), new ArrayList<>(e.getValue()));
}
return tmp;
}
private boolean addCondition(
Predicate predBody,
Predicate predHead,
RuleCompilationCondition cond) {
Map> condH = this.conditions.computeIfAbsent(predHead, k -> new HashMap<>());
List conditions = condH.computeIfAbsent(predBody, k -> new ArrayList<>());
if (!conditions.contains(cond)) {
conditions.add(cond);
return true;
} else {
return false;
}
}
private List extractCompilable(RuleBase rb) {
Iterator ruleSet = rb.getRules().iterator();
List compilable = new ArrayList<>();
Set toRemove = new HashSet<>();
while (ruleSet.hasNext()) {
FORule r = ruleSet.next();
if (this.isCompilable(r)) {
compilable.add(r);
toRemove.add(r);
}
}
for(FORule r : toRemove) {
rb.remove(r);
}
return compilable;
}
private boolean isCompilable(FORule r) {
return r.getBody().asAtomSet().size() == 1 &&
r.getHead().asAtomSet().size() == 1 &&
r.getExistentials().isEmpty() &&
r.getConstants().isEmpty();
}
private void createIDCondition(Iterator compilable) {
while (compilable.hasNext()) {
FORule ru = compilable.next();
Atom b = ru.getBody().asAtomSet().iterator().next();
Atom h = ru.getHead().asAtomSet().iterator().next();
this.addCompilation(b, h);
}
}
}