fr.boreal.model.ruleCompilation.id.IDRuleCompilationCondition Maven / Gradle / Ivy
The newest version!
package fr.boreal.model.ruleCompilation.id;
import fr.boreal.model.logicalElements.api.*;
import fr.boreal.model.logicalElements.factory.api.TermFactory;
import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
import fr.boreal.model.partition.Partition;
import fr.boreal.model.partition.TermPartition;
import fr.boreal.model.ruleCompilation.api.RuleCompilationCondition;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
/**
* Version as implemented by Melanie in graal
*/
public class IDRuleCompilationCondition implements RuleCompilationCondition {
private final TermFactory tf = SameObjectTermFactory.instance();
private final int[] condBody;
private final int[] condHead;
/**
* Create a new condition with the given encoding
* @param condBody the conditions on the body
* @param condHead the conditions on the head
*/
public IDRuleCompilationCondition(int[] condBody, int[] condHead) {
this.condBody = condBody;
this.condHead = condHead;
}
/**
* Create a new condition with the given body and head as array
* @param body the body
* @param head the head
*/
public IDRuleCompilationCondition(Term[] body, Term[] head) {
this(List.of(body), List.of(head));
}
/**
* Create a new condition with the given body and head as list
* @param body the body
* @param head the head
*/
public IDRuleCompilationCondition(List body, List head) {
// code the condition on the body terms
condBody = new int[body.size()];
int var = -1;
for (int i = 0; i < body.size(); ++i) {
condBody[i] = -1;
for (int j = 0; j < i; ++j) {
if (body.get(i).equals(body.get(j))) {
condBody[i] = condBody[j];
}
}
if (condBody[i] == -1) {
condBody[i] = ++var;
}
}
// code the condition on the head terms
condHead = new int[head.size()];
for (int j = 0; j < head.size(); j++) {
boolean found = false;
int i = 0;
while (!found && i < body.size()) {
if (body.get(i).equals(head.get(j))) {
found = true;
condHead[j] = condBody[i];
}
i++;
}
}
}
@Override
public boolean check(Atom a, Atom b) {
List body = List.of(a.getTerms());
List head = List.of(b.getTerms());
// check the condition on the body terms
if (body.size() != condBody.length)
return false;
Term[] check = new Term[body.size()];
for (int i = 0; i < condBody.length; i++) {
if (check[condBody[i]] == null) {
check[condBody[i]] = body.get(i);
} else if (!Objects.equals(body.get(i), check[condBody[i]])) {
return false;
}
}
// check the condition on the head terms
if (head.size() != condHead.length)
return false;
for (int i = 0; i < head.size(); i++) {
if (!head.get(i).equals(check[condHead[i]]))
return false;
}
return true;
}
@Override
public Pair, Substitution> instantiate(List head) {
Substitution s = new SubstitutionImpl();
Set toRemoveFromPartition = new HashSet<>();
Map freshVar = new HashMap<>();
for (int i = 0; i < condHead.length; i++) {
Variable v = freshVar.getOrDefault(condHead[i], this.tf.createOrGetFreshVariable());
freshVar.put(condHead[i], v);
toRemoveFromPartition.add(v);
Substitution s2 = new SubstitutionImpl();
s2.add(v, head.get(i));
Optional merged = s.merged(s2);
if(merged.isEmpty()) {
return null;
} else {
s = merged.get();
}
}
List body = new ArrayList<>(condBody.length);
for (int j : condBody) {
Variable v = freshVar.getOrDefault(j, this.tf.createOrGetFreshVariable());
toRemoveFromPartition.add(v);
body.add(s.createImageOf(v));
}
for (Variable v : toRemoveFromPartition) {
s.remove(v);
}
return new ImmutablePair<>(body, s);
}
@Override
public RuleCompilationCondition composeWith(RuleCompilationCondition condition) {
if(condition instanceof IDRuleCompilationCondition) {
return this.composeWith((IDRuleCompilationCondition)condition);
}
return null;
}
private IDRuleCompilationCondition composeWith(IDRuleCompilationCondition condition) {
int[] newCondBody = new int[this.condBody.length];
int[] newCondHead = new int[condition.condHead.length];
// generate a partition representing variables to unify
Partition partition = new Partition<>();
for (int i = 0; i < this.condHead.length; ++i) {
partition.addClass(Set.of(this.condHead[i] * 2, condition.condBody[i] * 2 + 1));
}
// generate new body
for (int i = 0; i < newCondBody.length; ++i) {
newCondBody[i] = partition.getRepresentative(this.condBody[i] * 2);
}
// generate new head
for (int i = 0; i < newCondHead.length; ++i) {
newCondHead[i] = partition.getRepresentative(condition.condHead[i] * 2 + 1);
}
// normalize index
int var = -1;
int[] map = new int[newCondBody.length * 2 + 1];
Arrays.fill(map, -1);
for (int i = 0; i < newCondBody.length; ++i) {
if (map[newCondBody[i]] == -1) {
map[newCondBody[i]] = ++var;
}
newCondBody[i] = map[newCondBody[i]];
}
for (int i = 0; i < newCondHead.length; ++i) {
newCondHead[i] = map[newCondHead[i]];
}
return new IDRuleCompilationCondition(newCondBody, newCondHead);
}
@Override
public boolean isIdentity() {
return Arrays.equals(condBody, condHead);
}
@Override
public Substitution homomorphism(List head, List to, Substitution initialSub) {
if (!checkBody(to)) {
return null;
}
Pair, Substitution> ret = this.instantiate(head);
if (ret == null) {
return null;
}
Substitution s = ret.getRight();
Substitution homo = new SubstitutionImpl();
List generatedBody = ret.getLeft();
if(generatedBody.contains(null)) {
return null;
}
// check for a simple homomorphism from generated body into 'to'
Iterator itFrom = generatedBody.iterator();
Iterator itTo = to.iterator();
while (itFrom.hasNext() && itTo.hasNext()) {
Term termFrom = itFrom.next();
Term termTo = itTo.next();
if (termFrom.isFrozen(initialSub)) {
if (!initialSub.createImageOf(termFrom).equals(termTo)) {
return null;
}
} else if (termFrom.isFunctionalTerm()) {
if(termTo.isFunctionalTerm()) {
Substitution innerRes = ((FunctionalTerm)termFrom).homomorphism((FunctionalTerm)termTo, s);
if(innerRes == null) {
return null;
} else {
homo = homo.merged(innerRes).orElse(null);
if(homo == null) {
return null;
}
}
} else {
return null;
}
} else {
homo.add((Variable) termFrom, termTo);
}
}
if (itFrom.hasNext() || itTo.hasNext()) {
throw new Error("Wrong term number");
}
// apply homo found over Substitution s from generateBody and add it to
// homo
for (Variable t : s.keys()) {
homo.add(t, homo.createImageOf(s.createImageOf(t)));
}
return homo;
}
@Override
public TermPartition unifier(Atom a, Atom b) {
List body = List.of(a.getTerms());
List head = List.of(b.getTerms());
TermPartition res = new TermPartition();
Term[] map = new Term[body.size()];
// put together term of body that must be unified according to this
for (int i = 0; i < condBody.length; ++i) {
Term t = body.get(i);
if (map[condBody[i]] == null) {
map[condBody[i]] = t;
} else {
res.addClass(Set.of(map[condBody[i]], t));
}
}
// put term of head into the class of the corresponding term of body
// according this
for (int i = 0; i < condHead.length; i++) {
Term t = head.get(i);
res.addClass(Set.of(map[condHead[i]], t));
}
return res;
}
/**
* Return true iff the given term fulfills the condition on the body term of
* this
*/
private boolean checkBody(List body) {
if (body.size() != condBody.length)
return false;
Term[] check = new Term[body.size()];
for (int i = 0; i < condBody.length; i++) {
if (check[condBody[i]] == null) {
check[condBody[i]] = body.get(i);
} else if (!check[condBody[i]].equals(body.get(i))) {
return false;
}
}
return true;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof IDRuleCompilationCondition other)) {
return false;
}
return Arrays.equals(this.condBody, other.condBody) && Arrays.equals(this.condHead, other.condHead);
}
@Override
public String toString() {
boolean isFirst = true;
StringBuilder s = new StringBuilder("([");
for (int j : condBody) {
if (isFirst) {
isFirst = false;
} else {
s.append(" ");
}
s.append(j);
}
s.append("] -> [");
isFirst = true;
for (Integer i : condHead) {
if (isFirst) {
isFirst = false;
} else {
s.append(" ");
}
s.append(i);
}
s.append("])");
return s.toString();
}
}