fr.lirmm.graphik.integraal.homomorphism.bbc.BCCScheduler 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
/*
* 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.homomorphism.bbc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.mutable.MutableInt;
import fr.lirmm.graphik.integraal.api.core.Atom;
import fr.lirmm.graphik.integraal.api.core.AtomSet;
import fr.lirmm.graphik.integraal.api.core.InMemoryAtomSet;
import fr.lirmm.graphik.integraal.api.core.RulesCompilation;
import fr.lirmm.graphik.integraal.api.core.Term;
import fr.lirmm.graphik.integraal.api.core.Variable;
import fr.lirmm.graphik.integraal.api.store.Store;
import fr.lirmm.graphik.integraal.homomorphism.Var;
import fr.lirmm.graphik.integraal.homomorphism.VarSharedData;
import fr.lirmm.graphik.integraal.homomorphism.scheduler.AbstractScheduler;
import fr.lirmm.graphik.integraal.homomorphism.scheduler.Scheduler;
import fr.lirmm.graphik.integraal.homomorphism.utils.ProbaUtils;
import fr.lirmm.graphik.util.graph.DefaultDirectedEdge;
import fr.lirmm.graphik.util.graph.DefaultGraph;
import fr.lirmm.graphik.util.graph.DefaultHyperEdge;
import fr.lirmm.graphik.util.graph.DefaultHyperGraph;
import fr.lirmm.graphik.util.graph.DirectedEdge;
import fr.lirmm.graphik.util.graph.Graph;
import fr.lirmm.graphik.util.graph.HyperGraph;
import fr.lirmm.graphik.util.stream.CloseableIteratorWithoutException;
class BCCScheduler extends AbstractScheduler implements Scheduler {
protected final BCC BCC;
private Comparator varComparator;
private Term[] inverseMap;
boolean withForbiddenCandidate;
private double ansVariableFactor = 1E-4;
/**
*
* @param BCC
* @param withForbiddenCandidate
*/
BCCScheduler(BCC BCC, boolean withForbiddenCandidate) {
this.BCC = BCC;
this.withForbiddenCandidate = withForbiddenCandidate;
}
/**
*
* @param BCC
* @param withForbiddenCandidate
* @param ansVariableFactor must be in ]0, 1], where a small value favours answer variables.
* A value of one means that answer variables will not be avantageous.
*/
BCCScheduler(BCC BCC, boolean withForbiddenCandidate, double ansVariableFactor) {
this.BCC = BCC;
this.withForbiddenCandidate = withForbiddenCandidate;
if(ansVariableFactor > 0 && ansVariableFactor <=1) {
this.ansVariableFactor = ansVariableFactor;
}
}
@Override
public VarSharedData[] execute(InMemoryAtomSet query, Set preAffectedVars, List ans, AtomSet data,
RulesCompilation rc) {
InMemoryAtomSet fixedQuery = (preAffectedVars.isEmpty())? query : computeFixedQuery(query, preAffectedVars);
// Term index
Set variables = fixedQuery.getVariables();
Map map = new HashMap();
this.inverseMap = new Term[variables.size() + 1];
{ // init indexes
int i = 0;
for (Variable t : variables) {
inverseMap[++i] = t;
map.put(t, i);
}
}
HyperGraph graph = constructHyperGraph(fixedQuery, variables.size(), this.inverseMap, map, ans);
double[] proba;
if(data instanceof Store) {
proba = this.computeProba(fixedQuery, (Store) data, variables.size(), map, rc);
} else {
proba = new double[variables.size() + 1];
Arrays.fill(proba, 1);
}
// bias proba of answer variables
for(Term t : ans) {
if(variables.contains(t)) {
int idx = map.get(t);
proba[idx] *= ansVariableFactor;
}
}
this.varComparator = new IntegerComparator(proba);
TmpData d = biconnect(graph, this.varComparator);
VarSharedData[] vars = new VarSharedData[variables.size() + 2];
this.BCC.varData = new VarData[variables.size() + 2];
vars[0] = new VarSharedData(0);
this.BCC.varData[0] = new VarData();
int lastAnswerVariable = -1;
for (int i = 1; i < d.vars.length; ++i) {
VarSharedData v = d.vars[i];
vars[v.level] = v;
this.BCC.varData[v.level] = d.ext[i];
v.value = (Variable) this.inverseMap[i];
v.nextLevel = v.level + 1;
v.previousLevel = v.level - 1;
if (this.withForbiddenCandidate && this.BCC.varData[v.level].isAccesseur) {
this.BCC.varData[v.level].forbidden = new HashSet();
}
if (ans.contains(v.value)) {
if (v.level > lastAnswerVariable)
lastAnswerVariable = v.level;
}
}
int level = variables.size() + 1;
vars[level] = new VarSharedData(level);
this.BCC.varData[level] = new VarData();
// if an homomorphism is found, go to the last answer variable
vars[level].previousLevel = lastAnswerVariable;
// Profiling
if (this.getProfiler().isProfilingEnabled()) {
StringBuilder sb = new StringBuilder();
for (VarSharedData v : vars) {
sb.append(v.value);
sb.append(" > ");
}
this.getProfiler().put("BCCOrder", sb.toString());
}
return vars;
}
@Override
public void clear() {
for(VarData d :this.BCC.varData) {
d.clear();
}
}
@Override
public boolean isAllowed(Var var, Term image) {
return (this.BCC.varData[var.shared.level].forbidden == null
|| !this.BCC.varData[var.shared.level].forbidden.contains(image));
}
/**
*
* @param h
* @param data
* @param nbVar
* @param map
* @param rc
* @return the probability to have an image for each variables which appears
* in h.
*/
protected double[] computeProba(InMemoryAtomSet h, Store data, int nbVar, Map map,
RulesCompilation rc) {
final double[] proba = new double[nbVar + 1];
Arrays.fill(proba, -1.);
CloseableIteratorWithoutException it = h.iterator();
while (it.hasNext()) {
Atom a = it.next();
double probaA = ProbaUtils.computeProba(a, data, rc);
for (Term t : a.getVariables()) {
int i = map.get(t);
if (proba[i] < 0) {
proba[i] = probaA;
} else {
proba[i] *= probaA;
}
}
}
return proba;
}
protected static TmpData biconnect(HyperGraph g, Comparator varComparator) {
TmpData d = new TmpData(g.nbVertices());
d.components = new ArrayList>();
d.i = 0;
d.stack = new LinkedList();
d.lowpt = new int[g.nbVertices()];
List vertices = new LinkedList();
for (int v = 1; v < g.nbVertices(); ++v) {
vertices.add(v);
}
Collections.sort(vertices, varComparator);
for (Integer v : vertices) {
if (d.vars[v].level == 0) {
biconnect(g, d, v, 0, varComparator);
}
}
return d;
}
protected static void biconnect(HyperGraph g, TmpData d, int v, int u, Comparator varComparator) {
Deque lastAccesseurs = new LinkedList();
MutableInt lastTerminal = new MutableInt(0);
biconnect(g, d, v, u, varComparator, lastAccesseurs, lastTerminal);
}
protected static void biconnect(HyperGraph g, TmpData d, int v, int u, Comparator varComparator,Deque lastAccesseurs, MutableInt lastTerminal) {
d.lowpt[v] = d.vars[v].level = ++d.i;
d.ext[v].previousLevelFailure = d.vars[u].level;
Iterator adjacencyIt = g.adjacencyList(v);
LinkedList list = new LinkedList();
while (adjacencyIt.hasNext()) {
list.add(adjacencyIt.next());
}
Collections.sort(list, varComparator);
adjacencyIt = list.iterator();
int w;
while (adjacencyIt.hasNext()) {
w = adjacencyIt.next();
if (d.vars[w].level == 0) {
d.stack.push(new DefaultDirectedEdge(v, w));
biconnect(g, d, w, v, varComparator);
d.lowpt[v] = Math.min(d.lowpt[v], d.lowpt[w]);
if (d.lowpt[w] >= d.vars[v].level) {
// start new component
d.currentComponent = new HashSet();
d.components.add(d.currentComponent);
while (d.vars[d.stack.peek().getTail()].level >= d.vars[w].level) {
DirectedEdge e = d.stack.pop();
d.currentComponent.add(e.getTail());
d.currentComponent.add(e.getHead());
}
// should be (w, v)
DirectedEdge e = d.stack.pop();
d.currentComponent.add(e.getTail());
d.currentComponent.add(e.getHead());
int entry = w;
int accesseur = (u == 0) ? u : v;
int terminal = v;
d.ext[accesseur].isAccesseur = true;
for (int i : d.currentComponent) {
if ((u == 0 || i != v) && d.vars[i].level < d.vars[entry].level) {
entry = i;
}
if (d.vars[i].level > d.vars[terminal].level) {
terminal = i;
}
if (i != v) {
d.ext[i].accesseur = d.vars[accesseur].level;
}
}
d.ext[entry].isEntry = true;
int componentVertice = d.bccGraph.addComponent(d.currentComponent);
int accesseurVertice = d.bccGraph.addAccesseur(accesseur);
d.bccGraph.addEdge(componentVertice, accesseurVertice);
if (!lastAccesseurs.isEmpty() && d.vars[lastAccesseurs.peek()].level >= d.vars[entry].level) {
while (!lastAccesseurs.isEmpty()
&& d.vars[lastAccesseurs.peek()].level >= d.vars[entry].level) {
int a = lastAccesseurs.pop();
if (a != accesseur) {
d.bccGraph.addEdge(componentVertice, d.bccGraph.addAccesseur(a));
}
}
} else {
d.ext[terminal].isTerminal = true;
d.ext[terminal].compilateurs = new TreeSet();
lastTerminal.setValue(terminal);
}
d.ext[lastTerminal.getValue()].compilateurs.add(d.vars[entry].level);
if (lastAccesseurs.isEmpty() || lastAccesseurs.peek() != accesseur) {
lastAccesseurs.push(accesseur);
}
}
} else if (d.vars[w].level < d.vars[v].level && w != u) {
d.stack.push(new DefaultDirectedEdge(v, w));
d.lowpt[v] = Math.min(d.lowpt[v], d.vars[w].level);
}
}
}
/**
* The HyperGraph of variables of h. There is an hyper edge between a set of
* variables if they appear in a same atom.
*
* @param h
* @return the HyperGraph of variables of h.
*/
protected static HyperGraph constructHyperGraph(InMemoryAtomSet h, int nbVariables, Term[] inverseMap,
Map map, Iterable ans) {
HyperGraph graph = new DefaultHyperGraph(nbVariables + 1);
CloseableIteratorWithoutException it = h.iterator();
while (it.hasNext()) {
Atom a = it.next();
DefaultHyperEdge edge = new DefaultHyperEdge();
int arity = 0;
for (Variable t : a.getVariables()) {
++arity;
edge.addVertice(map.get(t));
}
if(arity >= 2) {
graph.add(edge);
}
}
return graph;
}
// /////////////////////////////////////////////////////////////////////////
// PRIVATE CLASS
// /////////////////////////////////////////////////////////////////////////
protected static class TmpData {
VarSharedData[] vars;
VarData[] ext;
int i;
int lowpt[];
Deque stack;
List> components;
Set currentComponent;
BCCGraph bccGraph = new BCCGraph();
TmpData(int nbVertices) {
vars = new VarSharedData[nbVertices];
ext = new VarData[nbVertices];
for (int i = 0; i < nbVertices; ++i) {
vars[i] = new VarSharedData();
ext[i] = new VarData();
}
}
}
protected static class BCCGraph {
public Graph graph = new DefaultGraph();
private List