fr.lirmm.boreal.util.Rules Maven / Gradle / Ivy
Show all versions of integraal-util Show documentation
package fr.lirmm.boreal.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.Sets;
import fr.boreal.model.formula.FOFormulas;
import fr.boreal.model.formula.api.FOFormula;
import fr.boreal.model.formula.api.FOFormulaConjunction;
import fr.boreal.model.formula.api.FOFormulaNegation;
import fr.boreal.model.formula.factory.FOFormulaFactory;
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.api.Variable;
import fr.boreal.model.logicalElements.factory.api.TermFactory;
import fr.boreal.model.logicalElements.factory.impl.SameObjectPredicateFactory;
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.rule.api.FORule;
import fr.boreal.model.rule.impl.FORuleImpl;
/**
* Utility class for rules
*/
public final class Rules {
/**
* Generate a set of mono-piece rules equivalent of the specified rule.
*
* @param rule rule to split into single piece
* @return a Collection of Rule which is a decomposition of the specified rule to single piece rules.
*/
public static Collection computeSinglePiece(FORule rule) {
Collection monoPiece = new LinkedList<>();
PiecesSplitter splitter = new PiecesSplitter(true, rule.getExistentials());
for (Collection piece : splitter.split(rule.getHead().asAtomSet())) {
Collection piece_as_formula = new HashSet<>(piece);
monoPiece.add(new FORuleImpl(
rule.getBody(),
FOFormulaFactory.instance().createOrGetConjunction(piece_as_formula)));
}
return monoPiece;
}
/**
* @param rule the rule to get the positive part of the body
* @return the conjunction representing the positive parts of the body of the given rule
*/
public static FOFormula getPositiveBodyPart(FORule rule) {
Set bodyPositive = new HashSet<>();
FOFormula body = rule.getBody();
if(body.isAtomic()) {
bodyPositive.add(body);
} else if(body.isDisjunction()) {
throw new UnsupportedOperationException("Cannot decompose a disjunctive rule into positive part.");
} else if(body.isNegation()) {
// Do nothing
} else if(body.isConjunction()) {
for(FOFormula f : ((FOFormulaConjunction)body).getSubElements()) {
if(f.isAtomic()) {
bodyPositive.add(f);
} else if(f.isNegation()) {
// Do nothing
} else {
throw new UnsupportedOperationException("Cannot decompose a rule with multiple layers of imbrication into positive parts.");
}
}
} else {
throw new UnsupportedOperationException("Unsupported rule type for rule : " + rule);
}
return FOFormulaFactory.instance().createOrGetConjunction(bodyPositive);
}
/**
* @param rule the rule to get the negative parts of the body
* @return the conjunction representing the negative parts of the body of the given rule
*/
public static FOFormula getNegativeBodyParts(FORule rule) {
Set negativeParts = new HashSet<>();
FOFormula body = rule.getBody();
if(body.isAtomic()) {
// Do nothing
} else if(body.isDisjunction()) {
throw new UnsupportedOperationException("Cannot decompose a disjunctive rule into negative parts.");
} else if(body.isNegation()) {
negativeParts.add(body);
} else if(body.isConjunction()) {
for(FOFormula f : ((FOFormulaConjunction)body).getSubElements()) {
if(f.isAtomic()) {
// Do nothing
} else if(f.isNegation()) {
negativeParts.add(((FOFormulaNegation)f).element());
} else {
throw new UnsupportedOperationException("Cannot decompose a rule with multiple layers of imbrication into negative parts.");
}
}
} else {
throw new UnsupportedOperationException("Unsupported rule type for rule : " + rule);
}
return FOFormulaFactory.instance().createOrGetConjunction(negativeParts);
}
/**
* Generate a set of safe-negative rules equivalent of the specified rule.
* A rule is safe-negative iff each negative part contains only variables that appear in the positive part.
*
* Let R a rule,
* B+ the positive part of R,
* B- = A1, ..., Ak a negative part of R
*
* This decomposition replaces each B- by a new atom and
* adds a rule R' = B- -> p(x1, ..., xj) where x1, ..., xj are the variables that appear both in B+ and B-.
*
* @param rule rule to decompose into safe negation
* @return a Collection of rule which is a decomposition of the specified rule to safe-negation rules.
*/
public static Collection computeSafeNegation(FORule rule) {
Set safeNegative = new HashSet<>();
Set bodyPositive = new HashSet<>();
Set negativeParts = new HashSet<>();
FOFormula body = rule.getBody();
if(body.isAtomic()) {
safeNegative.add(rule);
} else if(body.isDisjunction()) {
throw new UnsupportedOperationException("Cannot decompose a disjunctive rule into safe-negation.");
} else if(body.isNegation()) {
negativeParts.add(body);
} else if(body.isConjunction()) {
for(FOFormula f : ((FOFormulaConjunction)body).getSubElements()) {
if(f.isAtomic()) {
bodyPositive.add(f);
} else if(f.isNegation()) {
negativeParts.add(((FOFormulaNegation)f).element());
} else {
throw new UnsupportedOperationException("Cannot decompose a rule with multiple layers of imbrication into safe-negation.");
}
}
} else {
throw new UnsupportedOperationException("Unsupported rule type for rule : " + rule);
}
for(FOFormula negativePart : negativeParts) {
Set bodyPositiveVariables = bodyPositive.stream()
.map(FOFormula::getVariables)
.flatMap(Set::stream)
.collect(Collectors.toSet());
List linkedVariables = new ArrayList<>(Sets.intersection(bodyPositiveVariables, negativePart.getVariables()));
Predicate freshPredicate = SameObjectPredicateFactory.instance().createOrGetFreshPredicate(linkedVariables.size());
Atom helper = new AtomImpl(freshPredicate, linkedVariables);
FORule helperPositiveRule = new FORuleImpl(negativePart, helper);
safeNegative.add(helperPositiveRule);
FOFormula notHelper = FOFormulaFactory.instance().createOrGetNegation(helper);
FOFormula safeBody = FOFormulaFactory.instance().createOrGetConjunction(Sets.union(bodyPositive, Set.of(notHelper)));
FORule safeInitialRule = new FORuleImpl(safeBody, rule.getHead());
safeNegative.add(safeInitialRule);
}
return safeNegative;
}
/**
* Create a new rule corresponding to the given rule by renaming all the variables with fresh variables
*
* @param rule to rename
* @return a new rule corresponding to the given rule by renaming all the variables with fresh variables
*/
public static FORule freshRenaming(FORule rule) {
TermFactory tf = SameObjectTermFactory.instance();
Substitution s = new SubstitutionImpl();
for(Variable v : rule.getBody().getVariables()) {
if(!s.keys().contains(v)) {
s.add(v, tf.createOrGetFreshVariable());
}
}
for(Variable v : rule.getHead().getVariables()) {
if(!s.keys().contains(v)) {
s.add(v, tf.createOrGetFreshVariable());
}
}
return Rules.createImageWith(rule, s);
}
/**
* @param r the rule to apply the substitution on
* @param s the substitution to apply
* @return a new FORule corresponding to the given FORule in which the
* given substitution have been applied
*/
public static FORule createImageWith(FORule r, Substitution s) {
FOFormula body = FOFormulas.createImageWith(r.getBody(), s);
FOFormula head = FOFormulas.createImageWith(r.getHead(), s);
return new FORuleImpl(body, head);
}
}