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

fr.boreal.forgetting.Forgetting Maven / Gradle / Ivy

The newest version!
package fr.boreal.forgetting;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import fr.boreal.backward_chaining.core.QueryCoreProcessorImpl;
import fr.boreal.backward_chaining.pure.PureRewriter;
import fr.boreal.model.formula.FOFormulas;
import fr.boreal.model.formula.api.FOFormula;
import fr.boreal.model.formula.factory.FOFormulaFactory;
import fr.boreal.model.kb.api.RuleBase;
import fr.boreal.model.kb.impl.RuleBaseImpl;
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.Variable;
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.query.api.FOQuery;
import fr.boreal.model.query.factory.FOQueryFactory;
import fr.boreal.model.rule.api.FORule;
import fr.boreal.model.rule.impl.FORuleImpl;
import fr.boreal.redundancy.Redundancy;
import fr.boreal.unifier.QueryUnifier;
import fr.boreal.unifier.QueryUnifierAlgorithm;


/**
 * The process of Forgetting is to remove some rules from the rulebase according to specific properties.
 * 

* The goal is to obtain an equivalent rulebase (in terms of end-inferences) by short-cutting some inferences, * removing some predicates from the inferred vocabulary. *

* This work is done for datalog rules. * * @author Florent Tornil * */ public class Forgetting { private static final TermFactory termFactory = SameObjectTermFactory.instance(); private static final FOFormulaFactory formulaFactory = FOFormulaFactory.instance(); private static final FOQueryFactory queryFactory = FOQueryFactory.instance(); private static final PureRewriter rw = new PureRewriter(); private static final QueryCoreProcessorImpl coreProcessor = new QueryCoreProcessorImpl(); /** * Rewrite the bodies of all rules with using a query-rewriting algorithm * @param rb a rule base * @return a semantically equivalent superset of the original rule base */ public static RuleBase bodyUnfolding(RuleBase rb){ return new RuleBaseImpl(bodyUnfoldingWith(rb, rb.getRules())); } /** * Rewrites the rules' bodies in the given {@code toRewrite} collection using the given RuleBase. *

* The rules occurring only in {@code rb} will not be present in the returned rules. * Each body rewriting results in a new rule, where the head is a specialization of the * original one. *

*

* Note that this algorithm only halts if the rewriting process halts (ie: the RuleBase is FUS) *

* * @param rb rules used to unfold bodies * @param toRewrite rules that have to be body-unfolded * @return a new stream of {@code FORule} with all rewritings of {@code toRewrite} rules */ public static Collection bodyUnfoldingWith(RuleBase rb, Collection toRewrite) { Collection res = new HashSet<>(); for(FORule rule : toRewrite) { FOQuery q = queryFactory.createOrGetQuery(rule.getBody(), rule.getFrontier()); for(FOQuery rew : rw.rewrite(q, rb).getQueries()) { FOFormula body = rew.getFormula(); FOFormula head = FOFormulas.createImageWith(rule.getHead(), rew.getVariableEqualities().getAssociatedSubstitution(rew).orElseThrow()); res.add(new FORuleImpl(body, head)); } } return res; } /** * Creates a new RuleBase equivalent to the given one where some predicates have been removed from the vocabulary * *

* The given RuleBase is not modified *

* The given RuleBase must be FUS and all rules must be datalog *

* * @param rb RuleBase to apply the forgetting on * @param toDrop condition on predicates to remove * @return a new RuleBase equivalent to the given one with less vocabulary */ public static RuleBase naiveDatalogForget(RuleBase rb, java.util.function.Predicate toDrop){ Collection res = new HashSet<>(); for(FORule rule : bodyUnfolding(rb).getRules()) { if(!satisfies(rule, toDrop)) { res.add(rule); } } return new RuleBaseImpl(res); } /** * Creates a new RuleBase equivalent to the given one where some predicates have been removed from the vocabulary * *

* The given RuleBase is not modified *

* The given RuleBase must be FUS and all rules must be datalog *

* * @param rb RuleBase to apply the forgetting on * @param toDrop condition on predicates to remove * @return a new RuleBase equivalent to the given one with less vocabulary */ public static RuleBase semiNaiveDatalogForget(RuleBase rb, java.util.function.Predicate toDrop){ HashSet toKeep = new HashSet<>(); HashSet toRewrite = new HashSet<>(); HashSet forRewriting = new HashSet<>(); for (FORule rule : rb.getRules()){ if (satisfies(rule.getHead(), toDrop)){ forRewriting.add(rule); } else if (satisfies(rule.getBody(), toDrop)) { toRewrite.add(rule); } else { toKeep.add(rule); } } for(FORule rule : bodyUnfoldingWith(new RuleBaseImpl(forRewriting), toRewrite)) { if(!satisfies(rule, toDrop)) { toKeep.add(rule); } } return new RuleBaseImpl(toKeep); } /** * Creates a new RuleBase equivalent to the given one where some predicates have been removed from the vocabulary * *

* The given RuleBase is not modified *

* The given RuleBase must be FUS *

* * @param rb RuleBase to apply the forgetting on * @param toDrop condition on predicates to remove * @return a new RuleBase equivalent to the given one with less vocabulary */ public static RuleBase forget(RuleBase rb, java.util.function.Predicate toDrop) { Collection res = new HashSet<>(); for(FORule rule : closureByComposition(rb.getRules())) { if(!satisfies(rule.getBody(), toDrop)) { Collection filteredHead = new HashSet<>(); for (Atom atom : rule.getHead().asAtomSet()) { if (!toDrop.test(atom.getPredicate())) { filteredHead.add(atom); } } FOFormula head = formulaFactory.createOrGetConjunction(filteredHead); res.add(new FORuleImpl(rule.getBody(), head)); } } return new RuleBaseImpl(res); } /** * * @param r rule to check * @param condition to satisfy * @return true iff at least one predicate of the rule satisfies the condition */ private static boolean satisfies(FORule r, java.util.function.Predicate condition) { return satisfies(r.getHead(), condition) || satisfies(r.getBody(), condition); } /** * * @param f formula to check * @param condition to satisfy * @return true iff at least one predicate of the formula satisfies the condition */ private static boolean satisfies(FOFormula f, java.util.function.Predicate condition) { for(Predicate p : f.getPredicates()) { if(condition.test(p)) { return true; } } return false; } /** * Computes the closure of a given set of rules by the composition operator * *

* The given rules must be FUS *

* * @param rules to close by composition * @return the closure of rules by the composition operator */ private static Collection closureByComposition(Collection rules) { Collection closure = new HashSet<>(); Collection rulesToHandle = new HashSet<>(rules); while(!rulesToHandle.isEmpty()) { Collection newComposedRules = new HashSet<>(); for (FORule r1 : rulesToHandle) { for (FORule r2 : closure) { newComposedRules.addAll(ruleComposition(r1, r2)); } for (FORule r2 : rulesToHandle) { newComposedRules.addAll(ruleComposition(r1, r2)); } } for (FORule r1 : closure) { for (FORule r2 : rulesToHandle) { newComposedRules.addAll(ruleComposition(r1, r2)); } } closure.addAll(rulesToHandle); rulesToHandle.clear(); for(FORule composedRule : newComposedRules) { boolean isRedundant = false; for(FORule rule : closure) { isRedundant = isRedundant || Redundancy.ruleConsequence(new RuleBaseImpl(Set.of(rule)), composedRule); } for(FORule rule : rulesToHandle) { isRedundant = isRedundant || Redundancy.ruleConsequence(new RuleBaseImpl(Set.of(rule)), composedRule); } if(!isRedundant) { rulesToHandle.add(composedRule); } } } return closure; } /** * Compose the two given rules * @param r1 the first rule * @param r2 the second rule * @return the composed rules of r2 by r1 */ private static Collection ruleComposition(FORule r1, FORule r2) { Collection newRules = new HashSet<>(); Substitution s = new SubstitutionImpl(); for (Variable v : r1.getBody().getVariables()) { if (r2.getExistentials().contains(v) || r2.getBody().getVariables().contains(v)) { s.add(v, termFactory.createOrGetFreshVariable()); } } for (Variable v : r1.getExistentials()) { s.add(v, termFactory.createOrGetFreshVariable()); } FOQuery toRewrite = queryFactory.createOrGetQuery(FOFormulas.createImageWith(r1.getBody(), s), List.of(), null); Collection unifiers = new QueryUnifierAlgorithm().getMostGeneralSinglePieceUnifiers(toRewrite, r2); for (QueryUnifier u : unifiers) { Substitution s1 = u.getAssociatedSubstitution(); FOFormula newHead = formulaFactory.createOrGetConjunction( FOFormulas.createImageWith(r1.getHead(), s), FOFormulas.createImageWith(r2.getHead(), s1)); Collection newBody = new HashSet<>(toRewrite.getFormula().asAtomSet()); newBody.addAll(r2.getBody().asAtomSet()); newBody.removeAll(u.getUnifiedQueryPart().asAtomSet()); FOFormula q = FOFormulas.createImageWith(formulaFactory.createOrGetConjunction(newBody), s1); Collection frontier = new HashSet<>(q.getVariables()); frontier.retainAll(newHead.getVariables()); newHead = coreProcessor.computeCore(queryFactory.createOrGetQuery(newHead, frontier, null)).getFormula(); newRules.add(new FORuleImpl(q, newHead)); } return newRules; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy