All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy