fr.lirmm.graphik.integraal.core.Rules Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of integraal-graal-ruleset-analysis Show documentation
Show all versions of integraal-graal-ruleset-analysis Show documentation
Rule base analysis for InteGraal. This is imported from Graal
The newest version!
/*
* Copyright (C) Inria Sophia Antipolis - Méditerranée / LIRMM
* (Université de Montpellier & CNRS) (2014 - 2017)
*
* Contributors :
*
* Clément SIPIETER
* Mélanie KÖNIG
* Swan ROCHER
* Jean-François BAGET
* Michel LECLÈRE
* Marie-Laure MUGNIER
*
*
* This file is part of Graal .
*
* This software is governed by the CeCILL license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
/**
*
*/
package fr.lirmm.graphik.integraal.core;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
import fr.lirmm.graphik.integraal.GraalConstant;
import fr.lirmm.graphik.integraal.api.core.Atom;
import fr.lirmm.graphik.integraal.api.core.AtomSetException;
import fr.lirmm.graphik.integraal.api.core.InMemoryAtomSet;
import fr.lirmm.graphik.integraal.api.core.Predicate;
import fr.lirmm.graphik.integraal.api.core.Rule;
import fr.lirmm.graphik.integraal.api.core.Term;
import fr.lirmm.graphik.integraal.api.core.Variable;
import fr.lirmm.graphik.integraal.core.atomset.AtomSetUtils;
import fr.lirmm.graphik.integraal.core.atomset.DefaultInMemoryAtomSet;
import fr.lirmm.graphik.integraal.core.atomset.graph.DefaultInMemoryGraphStore;
import fr.lirmm.graphik.integraal.core.atomset.splitter.AtomSetSplitter;
import fr.lirmm.graphik.integraal.core.atomset.splitter.PiecesSplitter;
import fr.lirmm.graphik.integraal.core.factory.DefaultAtomFactory;
import fr.lirmm.graphik.integraal.core.factory.DefaultRuleFactory;
import fr.lirmm.graphik.util.stream.CloseableIterableWithoutException;
import fr.lirmm.graphik.util.stream.CloseableIteratorWithoutException;
import fr.lirmm.graphik.util.stream.IteratorException;
/**
* A set of tests and utilities for manipulating rules.
* @author Clément Sipieter (INRIA) {@literal }
*
*/
public final class Rules {
private Rules() {
}
/**
* Test if the body of the rule is atomic.
*
* @param rule
* @return true if and only if the body of the specified rule contains only
* one atom.
*/
public static boolean hasAtomicBody(Rule rule) {
return AtomSetUtils.isSingleton(rule.getBody());
}
/**
* Test if the head of the rule is atomic.
*
* @param rule
* @return true if and only if the head of the specified rule contains only
* one atom.
*/
public static boolean hasAtomicHead(Rule rule) {
return AtomSetUtils.isSingleton(rule.getHead());
}
public static boolean isThereOneAtomThatContainsAllVars(CloseableIterableWithoutException atomset,
Collection terms) {
CloseableIteratorWithoutException it = atomset.iterator();
while (it.hasNext()) {
Atom atom = it.next();
if (atom.getVariables().containsAll(terms)) {
return true;
}
}
return false;
}
/**
* Compute and return the set of pieces of the head according to the
* frontier. On Rules with Existential Variables: Walking the Decidability
* Line Jean-François Baget, Michel Leclère, Marie-Laure Mugnier, Eric
* Salvat
*
* @return a Collection ofInMemoryAtomSet representing the set of pieces of the head of the specified rule.
*/
public static Collection getPieces(Rule rule) {
AtomSetSplitter piecesSplitter = new PiecesSplitter(true, rule.getExistentials());
// In practice, we cannot have an exception because it is an InMemoryAtomSet
// But the Splitter can be used with any AtomSet and so, the signature of the method contains a throw declaration
// We must put a try that will never be used
try {
return piecesSplitter.split(rule.getHead());
} catch (IteratorException | AtomSetException e) {
e.printStackTrace();
}
return null;
}
// /////////////////////////////////////////////////////////////////////////
// TRANSFORM RULES
// /////////////////////////////////////////////////////////////////////////
/**
* Generate an iterator of mono-piece rules from an iterator of rules.
*
* @param rules
* a set of rules
* @return The equivalent set of mono-piece rules.
*/
public static SinglePieceRulesIterator computeSinglePiece(Iterator rules) {
return new SinglePieceRulesIterator(rules);
}
/**
* Generate an iterator of atomic head rules from an iterator of rules.
*
* @param rules
* a set of rules
* @return The equivalent set of atomic head rules.
*/
public static Iterator computeAtomicHead(Iterator rules) {
return new AtomicHeadIterator(new SinglePieceRulesIterator(rules));
}
/**
* Generate a set of mono-piece rules equivalent of the specified rule.
*
* @param rule
* @return a Collection of Rule which is a decomposition of the specified rule to single piece rules.
*/
public static Collection computeSinglePiece(Rule rule) {
String label = rule.getLabel();
Collection monoPiece = new LinkedList();
if (label.isEmpty()) {
for (InMemoryAtomSet piece : getPieces(rule)) {
monoPiece.add(DefaultRuleFactory.instance().create(rule.getBody(), piece));
}
} else {
int i = -1;
for (InMemoryAtomSet piece : getPieces(rule)) {
monoPiece.add(DefaultRuleFactory.instance().create(label + "-p" + ++i, rule
.getBody(), piece));
}
}
return monoPiece;
}
private static int auxIndex = -1;
/**
* Generate a set of atomic head rules equivalent of the specified rule.
*
* @param rule
* @return a Collection of Rule which is a decomposition of the specified rule to atomic head rules.
*/
public static Collection computeAtomicHead(Rule rule) {
String label = rule.getLabel();
Collection atomicHead = new LinkedList();
if (rule.getHead().isEmpty() || hasAtomicHead(rule)) {
return Collections. singleton(rule);
} else {
Predicate predicate = new Predicate("aux_" + ++auxIndex, rule.getTerms().size());
Atom aux = DefaultAtomFactory.instance().create(predicate,
rule.getTerms().toArray(new Term[rule.getTerms().size()]));
if (label.isEmpty()) {
atomicHead.add(DefaultRuleFactory.instance().create(rule.getBody(), new DefaultInMemoryAtomSet(aux)));
CloseableIteratorWithoutException it = rule.getHead().iterator();
while (it.hasNext()) {
Atom atom = it.next();
atomicHead.add(DefaultRuleFactory.instance().create(aux, atom));
}
} else {
int i = -1;
atomicHead.add(DefaultRuleFactory.instance().create(label + "-a" + ++i, rule.getBody(),
new DefaultInMemoryAtomSet(aux)));
CloseableIteratorWithoutException it = rule.getHead().iterator();
while (it.hasNext()) {
Atom atom = it.next();
atomicHead.add(DefaultRuleFactory.instance().create(label + "-a" + ++i, aux, atom));
}
}
}
return atomicHead;
}
// /////////////////////////////////////////////////////////////////////////
// ANALYSE KIND OF RULE
// /////////////////////////////////////////////////////////////////////////
public static boolean isConcept(Atom a) {
return a.getPredicate().getArity() == 1;
}
public static boolean isRole(Atom a) {
return a.getPredicate().getArity() == 2;
}
public static boolean isInclusion(Rule r) {
return hasAtomicBody(r) && hasAtomicHead(r);
}
public static boolean isConceptInclusion(Rule r) {
if (!isInclusion(r))
return false;
Atom C1 = r.getBody().iterator().next();
Atom C2 = r.getHead().iterator().next();
if (!isConcept(C1))
return false;
if (!isConcept(C2))
return false;
return C1.getTerm(0).equals(C2.getTerm(0));
}
public static boolean isRoleInclusion(Rule r) {
if (!isInclusion(r))
return false;
Atom P1 = r.getBody().iterator().next();
Atom P2 = r.getHead().iterator().next();
if (!isRole(P1))
return false;
if (!isRole(P2))
return false;
Term t1_1 = P1.getTerm(0);
Term t1_2 = P1.getTerm(1);
Term t2_1 = P2.getTerm(0);
Term t2_2 = P2.getTerm(1);
return (t1_1.equals(t2_1) && t1_2.equals(t2_2)) || (t1_1.equals(t2_2) && t1_2.equals(t2_1));
}
public static boolean isInverseRole(Rule r) {
if (!isRoleInclusion(r))
return false;
Atom P1 = r.getBody().iterator().next();
Atom P2 = r.getHead().iterator().next();
Term t1_1 = P1.getTerm(0);
Term t1_2 = P1.getTerm(1);
Term t2_1 = P2.getTerm(0);
Term t2_2 = P2.getTerm(1);
return t1_1.equals(t2_2) && t1_2.equals(t2_1);
}
public static boolean isSignature(Rule r) {
if (!isInclusion(r))
return false;
Atom P1 = r.getBody().iterator().next();
Atom C1 = r.getHead().iterator().next();
return isRole(P1) && isConcept(C1);
}
public static boolean isDomain(Rule r) {
if (!isSignature(r))
return false;
Atom P1 = r.getBody().iterator().next();
Atom C1 = r.getHead().iterator().next();
return P1.getTerm(0).equals(C1.getTerm(0));
}
public static boolean isRange(Rule r) {
if (!isSignature(r))
return false;
Atom P1 = r.getBody().iterator().next();
Atom C1 = r.getHead().iterator().next();
return P1.getTerm(1).equals(C1.getTerm(0));
}
public static boolean isMandatoryRole(Rule r) {
if (!isInclusion(r))
return false;
Atom C1 = r.getBody().iterator().next();
Atom P1 = r.getHead().iterator().next();
if (!isConcept(C1))
return false;
if (!isRole(P1))
return false;
return (C1.getTerm(0).equals(P1.getTerm(0)) && !C1.getTerm(0).equals(P1.getTerm(1)));
}
public static boolean isInvMandatoryRole(Rule r) {
if (!isInclusion(r))
return false;
Atom C1 = r.getBody().iterator().next();
Atom P1 = r.getHead().iterator().next();
if (!isConcept(C1))
return false;
if (!isRole(P1))
return false;
return (C1.getTerm(0).equals(P1.getTerm(1)) && !C1.getTerm(0).equals(P1.getTerm(0)));
}
public static boolean isExistRC(Rule r) {
if (!AtomSetUtils.isSingleton(r.getBody()))
return false;
if (!AtomSetUtils.hasSize2(r.getHead()))
return false;
CloseableIteratorWithoutException h = r.getHead().iterator();
Atom P1 = r.getBody().iterator().next();
Atom P2 = h.next();
Atom P3 = h.next();
Atom tmp;
if (!isConcept(P1))
return false;
if (isConcept(P2) && isRole(P3)) {
tmp = P2;
P2 = P3;
P3 = tmp;
}
if (!isRole(P2))
return false;
if (!isConcept(P3))
return false;
return (P1.getTerm(0).equals(P2.getTerm(0)) && P2.getTerm(1).equals(P3.getTerm(0)) && !P1.getTerm(0).equals(
P3.getTerm(0)));
}
public static boolean isInvExistRC(Rule r) {
if (!AtomSetUtils.isSingleton(r.getBody()))
return false;
if (!AtomSetUtils.hasSize2(r.getHead()))
return false;
CloseableIteratorWithoutException h = r.getHead().iterator();
Atom P1 = r.getBody().iterator().next();
Atom P2 = h.next();
Atom P3 = h.next();
Atom tmp;
if (!isConcept(P1))
return false;
if (isConcept(P2) && isRole(P3)) {
tmp = P2;
P2 = P3;
P3 = tmp;
}
if (!isRole(P2))
return false;
if (!isConcept(P3))
return false;
return (P1.getTerm(0).equals(P2.getTerm(1)) && P2.getTerm(0).equals(P3.getTerm(0)) && !P1.getTerm(0).equals(
P3.getTerm(0)));
}
public static boolean isRoleComposition(Rule r) {
if (!AtomSetUtils.hasSize2(r.getBody()))
return false;
if (!AtomSetUtils.isSingleton(r.getHead()))
return false;
CloseableIteratorWithoutException b = r.getBody().iterator();
Atom P1 = b.next();
Atom P2 = b.next();
Atom P3 = r.getHead().iterator().next();
if (!isRole(P1))
return false;
if (!isRole(P2))
return false;
if (!isRole(P3))
return false;
return (P1.getTerm(0).equals(P3.getTerm(0)) && P1.getTerm(1).equals(P2.getTerm(0)) && P2.getTerm(1).equals(
P3.getTerm(1)))
|| (P2.getTerm(0).equals(P3.getTerm(0)) && P2.getTerm(1).equals(P1.getTerm(0)) && P1.getTerm(1).equals(
P3.getTerm(1)));
}
public static boolean isTransitivity(Rule r) {
if (!isRoleComposition(r))
return false;
CloseableIteratorWithoutException b = r.getBody().iterator();
Atom P1 = b.next();
Atom P2 = b.next();
Atom P3 = r.getHead().iterator().next();
return P1.getPredicate().equals(P2.getPredicate()) && P1.getPredicate().equals(P3.getPredicate());
}
public static boolean isFunctional(Rule r) {
if (!AtomSetUtils.isSingleton(r.getHead()))
return false;
return r.getHead().iterator().next().getPredicate().equals(Predicate.EQUALITY);
}
public static boolean isNegativeConstraint(Rule r) {
if (!AtomSetUtils.isSingleton(r.getHead()))
return false;
return r.getHead().iterator().next().equals(DefaultAtomFactory.instance().getBottom());
}
public static boolean isDisjointConcept(Rule r) {
if (!AtomSetUtils.hasSize2(r.getBody()))
return false;
if (!isNegativeConstraint(r))
return false;
CloseableIteratorWithoutException b = r.getBody().iterator();
Atom C1 = b.next();
Atom C2 = b.next();
if (!isConcept(C1))
return false;
if (!isConcept(C2))
return false;
return (C1.getTerm(0).equals(C2.getTerm(0)));
}
public static boolean isDisjointRole(Rule r) {
if (!AtomSetUtils.hasSize2(r.getBody()))
return false;
if (!isNegativeConstraint(r))
return false;
CloseableIteratorWithoutException b = r.getBody().iterator();
Atom P1 = b.next();
Atom P2 = b.next();
if (!isRole(P1))
return false;
if (!isRole(P2))
return false;
return (P1.getTerm(0).equals(P2.getTerm(0)) && P1.getTerm(1).equals(P2.getTerm(1)))
|| (P1.getTerm(1).equals(P2.getTerm(0)) && P1.getTerm(0).equals(P2.getTerm(1)));
}
public static boolean isDisjointInverseRole(Rule r) {
if (!isDisjointRole(r))
return false;
CloseableIteratorWithoutException b = r.getBody().iterator();
Atom P1 = b.next();
Atom P2 = b.next();
return P1.getTerm(1).equals(P2.getTerm(0)) && P1.getTerm(0).equals(P2.getTerm(1));
}
// /////////////////////////////////////////////////////////////////////////
// Private classes
// /////////////////////////////////////////////////////////////////////////
private static class SinglePieceRulesIterator implements Iterator {
Iterator it;
Queue currentMonoPiece = new LinkedList();
Rule currentRule;
SinglePieceRulesIterator(Iterator iterator) {
this.it = iterator;
}
@Override
public boolean hasNext() {
return !currentMonoPiece.isEmpty() || it.hasNext();
}
@Override
public Rule next() {
if (currentMonoPiece.isEmpty()) {
currentRule = it.next();
currentMonoPiece
.addAll(Rules.computeSinglePiece(currentRule));
}
return currentMonoPiece.poll();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private static class AtomicHeadIterator implements Iterator {
Iterator it;
Queue currentAtomicHead = new LinkedList();
Rule currentRule;
AtomicHeadIterator(Iterator iterator) {
this.it = iterator;
}
@Override
public boolean hasNext() {
return !currentAtomicHead.isEmpty() || it.hasNext();
}
@Override
public Rule next() {
if (currentAtomicHead.isEmpty()) {
currentRule = it.next();
currentAtomicHead.addAll(Rules.computeAtomicHead(currentRule));
}
return currentAtomicHead.poll();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
public static InMemoryAtomSet criticalInstance(final Iterable rules) {
InMemoryAtomSet A = new DefaultInMemoryGraphStore();
criticalInstance(rules,A);
return A;
}
/**
* The skolem chase on the critical instance of R halts iff the skolem chase of R halts
* universally.
* The critical instance for a set of rules R contains all facts that can be constructed
* using all predicates occuring in R, all constants occurring in the body of a rule in R, and one
* special fresh constant.
*/
public static void criticalInstance(final Iterable rules, InMemoryAtomSet A) {
Set terms = new TreeSet();
terms.add(GraalConstant.freshConstant());
Set predicates = new TreeSet();
for (Rule r : rules) {
CloseableIteratorWithoutException it = r.getBody().iterator();
while (it.hasNext()) {
Atom b = it.next();
predicates.add(b.getPredicate());
for (Term t : b.getTerms())
if (t.isConstant())
terms.add(t);
}
}
// TODO: In the definition of CI, we need to add all
// predicates in rule head. But why? This doesn't make any
// sense...
for (Predicate p : predicates) {
generateCriticalInstance(A,terms,p,0,new DefaultAtom(p));
}
}
private static void generateCriticalInstance(InMemoryAtomSet A, Set terms, Predicate p, int position,
DefaultAtom a) {
if (position >= p.getArity()) {
A.add(a);
return;
}
for (Term t : terms) {
DefaultAtom a2 = new DefaultAtom(a);
a2.setTerm(position,t);
generateCriticalInstance(A,terms,p,position+1,a2);
}
}
};