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

fr.lirmm.boreal.util.Rules Maven / Gradle / Ivy

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 = piece.stream()
					.map(a -> a)
					.collect(Collectors.toSet());
			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).getElement());
				} 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).getElement());
				} 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);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy