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

fr.boreal.grd.impl.GRDImpl Maven / Gradle / Ivy

The newest version!
package fr.boreal.grd.impl;

import java.io.Serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.jgrapht.Graph;
import org.jgrapht.alg.connectivity.GabowStrongConnectivityInspector;
import org.jgrapht.alg.interfaces.ShortestPathAlgorithm.SingleSourcePaths;
import org.jgrapht.alg.shortestpath.BellmanFordShortestPath;
import org.jgrapht.alg.shortestpath.NegativeCycleDetectedException;
import org.jgrapht.graph.DirectedPseudograph;

import com.google.common.collect.Lists;

import fr.boreal.grd.api.GraphOfFORuleDependencies;
import fr.boreal.grd.impl.dependency_checker.DependencyChecker;
import fr.boreal.grd.impl.dependency_checker.ProductivityChecker;
import fr.boreal.model.formula.api.FOFormula;
import fr.boreal.model.kb.api.RuleBase;
import fr.boreal.model.kb.impl.RuleBaseImpl;
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.model.ruleCompilation.NoRuleCompilation;
import fr.boreal.model.ruleCompilation.api.RuleCompilation;
import fr.boreal.unifier.QueryUnifier;
import fr.boreal.unifier.QueryUnifierAlgorithm;
import fr.lirmm.boreal.util.Rules;

/**
 * GRD implementation using unification
 * 

* Rules of this GRD can have negation as long as the negation is safe */ public class GRDImpl extends DirectedPseudograph implements GraphOfFORuleDependencies { @Serial private static final long serialVersionUID = -1382791441537653245L; /** * Rulebase represented by this GRD */ private final RuleBase rulebase; /** * Compilation used on the rulebase */ private final RuleCompilation compilation; /** * Dependency checkers for a more precise GRD */ private final Collection checkers; /** * Constructor initialized with the rules from the rulebase * @param rulebase the ruleset to compute dependencies over * @param compilation compilation used on the ruleset * @param checkers checkers of the dependencies */ public GRDImpl(RuleBase rulebase, RuleCompilation compilation, Collection checkers) { super(GRDEdge.class); this.rulebase = rulebase; this.compilation = compilation; this.checkers = checkers; for(FORule r : this.getRules()) { this.addRule(r); } this.computeDependencies(); } /** * Constructor initialized with the rules from the rulebase no compilation and a productivity checker * @param ruleBase the ruleset to compute dependencies over */ public GRDImpl(RuleBase ruleBase) { this(ruleBase, NoRuleCompilation.instance(), List.of(ProductivityChecker.instance())); } /** * Constructor initialized with the rules from the rulebase and a productivity checker * @param ruleBase the ruleset to compute dependencies over * @param compilation compilation used on the ruleset */ public GRDImpl(RuleBase ruleBase, RuleCompilation compilation) { this(ruleBase, compilation, List.of(ProductivityChecker.instance())); } /** * Constructor initialized with the rules from the rulebase and no compilation * @param ruleBase the ruleset to compute dependencies over * @param checkers checkers of the dependencies */ public GRDImpl(RuleBase ruleBase, Collection checkers) { this(ruleBase, NoRuleCompilation.instance(), checkers); } // // // @Override public Collection getRules() { return this.rulebase.getRules(); } @Override public Set getTriggeredRules(FORule src) { Set triggeredRules = new HashSet<>(); for (GRDEdge edge : this.outgoingEdgesOf(src)) { if(edge.isPositive()) { triggeredRules.add(this.getEdgeTarget(edge)); } } return triggeredRules; } @Override public Set getPreventedRules(FORule src) { Set preventedRules = new HashSet<>(); for (GRDEdge edge : this.outgoingEdgesOf(src)) { if(!edge.isPositive()) { preventedRules.add(this.getEdgeTarget(edge)); } } return preventedRules; } @Override public boolean isStratifiable() { for(Graph component : this.getStronglyConnectedComponents()) { for(GRDEdge edge : component.edgeSet()) { if(!edge.isPositive()) { return false; } } } return true; } @Override public List getStratification() { List stratum = new ArrayList<>(); for(Graph component : this.getStronglyConnectedComponents()) { stratum.add(new RuleBaseImpl(component.vertexSet())); } return stratum; } @Override public Optional> getSingleEvaluationStratification() { List strates = new ArrayList(); GRDImpl graph = new GRDImpl(this.rulebase, this.compilation, this.checkers) { @Override public double getEdgeWeight(GRDEdge e) { return -1; } }; BellmanFordShortestPath bellmanFordAlgorithm = new BellmanFordShortestPath<>(graph); try { FORule fictiveSourceNode = new FORuleImpl(null, null); graph.addVertex(fictiveSourceNode); for(FORule r : graph.vertexSet()) { if(r != fictiveSourceNode) { GRDEdge edge = new GRDEdge(true); graph.addEdge(fictiveSourceNode, r, edge); } } SingleSourcePaths shortestPaths = bellmanFordAlgorithm.getPaths(fictiveSourceNode); graph.removeVertex(fictiveSourceNode); Map> rulesByCost = new HashMap>(); for(FORule r : graph.vertexSet()) { double cost = shortestPaths.getWeight(r); Set rulesInCost = rulesByCost.getOrDefault(cost, new HashSet()); rulesInCost.add(r); rulesByCost.put(cost, rulesInCost); } rulesByCost.keySet().stream() .sorted() .forEachOrdered(cost -> strates.add(new RuleBaseImpl(rulesByCost.get(cost)))); } catch (NegativeCycleDetectedException e) { return Optional.empty(); } return Optional.of(Lists.reverse(strates)); } @Override public Optional> getPseudoMinimalStratification() { List stratum = new ArrayList<>(); BellmanFordShortestPath bellmanFordAlgorithm = new BellmanFordShortestPath<>(this); try { FORule fictiveSourceNode = new FORuleImpl(null, null); this.addVertex(fictiveSourceNode); for(FORule r : this.vertexSet()) { if(r != fictiveSourceNode) { GRDEdge edge = new GRDEdge(true); this.addEdge(fictiveSourceNode, r, edge); } } SingleSourcePaths shortestPaths = bellmanFordAlgorithm.getPaths(fictiveSourceNode); this.removeVertex(fictiveSourceNode); Map> rulesByCost = new HashMap<>(); for(FORule r : this.vertexSet()) { double cost = shortestPaths.getWeight(r); Set rulesInCost = rulesByCost.getOrDefault(cost, new HashSet<>()); rulesInCost.add(r); rulesByCost.put(cost, rulesInCost); } rulesByCost.keySet().stream() .sorted() .forEachOrdered(cost -> stratum.add(new RuleBaseImpl(rulesByCost.get(cost)))); } catch (NegativeCycleDetectedException e) { return Optional.empty(); } return Optional.of(Lists.reverse(stratum)); } // // // @Override public double getEdgeWeight(GRDEdge e) { if(e.isPositive()) { return 0; } else { return -1; } } private void addRule(FORule r) { this.addVertex(r); } private void computeDependencies() { for(FORule r1 : this.vertexSet()) { for(FORule r2 : this.vertexSet()) { this.computeDependency(r1, r2); } } } private void computeDependency(FORule r1, FORule r2) { this.computePositiveDependency(r1, r2); this.computeNegativeDependency(r1, r2); } private void computePositiveDependency(FORule r1, FORule r2) { FORule r1safe = Rules.freshRenaming(r1); FORule r2safe = Rules.freshRenaming(r2); FOFormula r2bodyPositive = Rules.getPositiveBodyPart(r2safe); FOQuery r2query = FOQueryFactory.instance().createOrGetQuery(r2bodyPositive, Set.of(), null); QueryUnifierAlgorithm unifierAlgo = new QueryUnifierAlgorithm(this.compilation); Collection unifiers = unifierAlgo.getMostGeneralSinglePieceUnifiers(r2query, r1safe); for(QueryUnifier u : unifiers) { boolean isValid = true; for(DependencyChecker checker : this.checkers) { if(!checker.isValidPositiveDependency(r1safe, r2safe, u)) { isValid = false; break; } } if(isValid) { this.addEdge(r1, r2, new GRDEdge(true)); return; } } } private void computeNegativeDependency(FORule r1, FORule r2) { FORule r1safe = Rules.freshRenaming(r1); FORule r2safe = Rules.freshRenaming(r2); FOFormula r2bodyNegative = Rules.getNegativeBodyParts(r2safe); FOQuery r2query = FOQueryFactory.instance().createOrGetQuery(r2bodyNegative, Set.of(), null); QueryUnifierAlgorithm unifierAlgo = new QueryUnifierAlgorithm(this.compilation); Collection unifiers = unifierAlgo.getMostGeneralSinglePieceUnifiers(r2query, r1safe); for(QueryUnifier u : unifiers) { boolean isValid = true; for(DependencyChecker checker : this.checkers) { if(!checker.isValidNegativeDependency(r1safe, r2safe, u)) { isValid = false; break; } } if(isValid) { this.addEdge(r1, r2, new GRDEdge(false)); return; } } } private List> getStronglyConnectedComponents() { return Lists.reverse(new GabowStrongConnectivityInspector<>(this).getStronglyConnectedComponents()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy