package org.aksw.sparqlify.database;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import org.aksw.commons.collections.CartesianProduct;
import org.aksw.commons.collections.FlatMapView;
import org.aksw.jena_sparql_api.normal_form.Clause;
import org.aksw.jena_sparql_api.normal_form.Dnf;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.expr.Expr;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
class DnfIndex {
private Multimap<Var, Expr> singleVarExpr = HashMultimap.create();
//private Map<Clause> specific
// NOTE: Additions are conjunctive!
public void add(Dnf dnf) {
Collection<Clause> clauses = dnf.getClauses();
//dnf.getCommonExprs()
}
}
/**
*
* TODO Clarify: Do I want disjunctive or conjunctive normal form?
* (a and b) or (c and d) or
* (a or b) and(c or d) ?
* I guess the former is better, as (a and not a) can be easily detected
*
* What happens if we allow conjunctions of disjunctive normal forms?
* ((a, b) or (c, d) AND ((x) or (y)))
* becomes
* (abx or aby or cdx or cdy) (so the cross product of the involved clauses)
*
* Maybe i could do virtual clauses:
* CrossJoinClause(Clauses ...)
*
*
*
* Hm, but with CNF it is easier to add new expressions.
*
* @author Claus Stadler <cstadler@informatik.uni-leipzig.de>
*
*/
public class ExprIndex {
private ExprIndex parent;
// TODO I need this method due to the lack of suppert for CNF lookups on tables right now
public void getEffectiveDnf(Collection<Var> vars) {
}
/**
* I use this method for getting constraints for finding view candidates
*
*
* @param dnfs
* @param index
* @param dnfIndex
* @param blacklist
* @param depth
* @param parentClause
* @param result
*/
public void calcEffectiveClauses(final List<Dnf> dnfs, int index, final Set<Clause> blacklist, Clause parentClause, final Set<Clause> result) {
if(index >= dnfs.size()) {
if(parentClause != null) {
result.add(parentClause);
}
return;
}
Dnf dnf = dnfs.get(index);
for(Clause clause : dnf.getClauses()) {
if(blacklist.contains(clause)) {
continue;
}
Clause merged;
if(parentClause == null) {
merged = parentClause;
} else {
Set<Expr> exprs = new HashSet<Expr>(parentClause.getExprs());
exprs.addAll(clause.getExprs());
merged = new Clause(exprs);
calcEffectiveClauses(dnfs, index + 1, blacklist, merged, result);
}
}
}
/**
* This method is an ugly hack right, but I don't know
* where to better calculate it
*
* @return
*/
public Set<Clause> calcEffectiveClauses() {
Set<Clause> result = new HashSet<Clause>();
List<Collection<Clause>> tmp = new ArrayList<Collection<Clause>>();
for(Dnf dnf : dnfs) {
tmp.add(dnf.getClauses());
}
CartesianProduct<Clause> cartesian = CartesianProduct.create(tmp);
for(List<Clause> list : cartesian) {
Set<Expr> exprs = new HashSet<Expr>();
for(Clause c : list) {
exprs.addAll(c.getExprs());
}
result.add(new Clause(exprs));
}
return result;
}
public Set<Clause> getEffectiveClauses() {
return effectiveClauses;
}
private Set<Clause> effectiveClauses;
//private List<Dnf> dnfs = new ArrayList<Dnf>();
// The DNFs are sorted by number of clauses
private NavigableMap<Integer, Set<Dnf>> dnfGroups = new TreeMap<Integer, Set<Dnf>>();
private Collection<Dnf> dnfs = new FlatMapView<Dnf>(dnfGroups.values());
private Set<Var> varsMentioned = new HashSet<Var>();
//private Map<Var, Expr>
//private Map<Var, Expr> commonSingleVarExprs
//private Dnf dnf = new Dnf();
//private Map<Var, Clause> varToClauses = new HashMap<Var, Clause>();
//private ExprList exprs = new ExprList();
//private Multimap<Var, Expr> varToExprs = HashMultimap.create();
//VarExprList x;
//private Map<Var, PrefixSet> varToPrefixes = new HashMap<Var, PrefixSet>();
//private Map<Var>
public ExprIndex() {
}
public ExprIndex(ExprIndex parent) {
this.parent = parent;
/*
for(Dnf dnf : parent.getDnf()) {
add(dnf);
}*/
}
public ExprIndex(ExprIndex parent, Iterable<Expr> exprs) {
this.parent = parent;
addAll(exprs);
}
public ExprIndex(Set<Dnf> dnfs) {
addAll(dnfs);
}
public ExprIndex getParent() {
return parent;
}
public Collection<Dnf> getDnf() {
return dnfs;
}
public Set<Var> getVarsMentioned() {
return varsMentioned;
}
void add(Dnf dnf) {
int n = dnf.getClauses().size();
Set<Dnf> set = dnfGroups.get(n);
if(set == null) {
set = new HashSet<Dnf>();
dnfGroups.put(n, set);
}
set.add(dnf);
varsMentioned.addAll(dnf.getVarsMentioned());
this.effectiveClauses = calcEffectiveClauses();
}
void addAll(Collection<Dnf> dnfs) {
for(Dnf dnf : dnfs) {
add(dnf);
}
}
void add(Expr expr) {
Dnf dnf = Dnf.create(expr);
add(dnf);
//dnfs.add(dnf);
/*
exprs.add(expr);
for(Var var : exprs.getVarsMentioned()) {
varToExprs.put(var, expr);
}*/
//DnfUtils.toDnf(expr);
//varToExp
}
/**
* Any clause containing a var means, that in order for the clause to evaluate
* to true, the expression it is involved must be true.
*
* @param var
* @return
*/
public Set<Clause> getAllClausesWith(Var var) {
Set<Clause> result = new HashSet<Clause>();
for(Set<Dnf> dnfGroup : dnfGroups.values()) {
for(Dnf dnf : dnfGroup) {
Collection<Clause> clauses = dnf.get(var);
result.addAll(clauses);
}
}
return result;
}
public Set<Clause> getAllSingleVarExprs(Var var) {
Set<Clause> result = new HashSet<Clause>();
for(Set<Dnf> dnfGroup : dnfGroups.values()) {
for(Dnf dnf : dnfGroup) {
Collection<Clause> clauses = dnf.get(Collections.singleton(var));
result.addAll(clauses);
}
}
return result;
}
public void addAll(Iterable<Expr> exprs) {
for(Expr expr : exprs) {
add(expr);
}
}
@Override
public String toString() {
return dnfs.toString();
}
public ExprIndex filterByVars(Set<Var> requiredVars) {
//List<Dnf> filteredDnfs = new ArrayList<Dnf>();
ExprIndex result = new ExprIndex();
for(Set<Dnf> dnfGroup : dnfGroups.values()) {
for(Dnf dnf : dnfGroup) {
Set<Clause> clauses = dnf.filterByVars(requiredVars);
Dnf filteredDnf = new Dnf(clauses);
result.add(filteredDnf);
}
}
return result;
}
}
/*
class EffectiveClauseIterator
extends SinglePrefetchIterator<Clause>
{
//private ExprIndex dnfIndex;
private Set<Clause> blacklist;
private StackCartesianProductIterator<Clause> it;
public EffectiveClauseIterator(ExprIndex dnfIndex, Set<Clause> blacklist) {
Collection<Dnf> dnfs = dnfIndex.getDnf();
List<Collection<Clause>> clauses = new ArrayList<Collection<Clause>>();
for(Dnf dnf : dnfs) {
clauses.add(dnf.getClauses());
}
//DescenderIterator<Clause> it = new DescenderIterator<Clause>(clauses, )
this.it = new StackCartesianProductIterator<Clause>(clauses);
}
@Override
protected Clause prefetch() throws Exception {
while(it.hasNext()) {
List<Clause> item = it.next();
Clause newClause = item.get(item.size() - 1);
if(blacklist.contains(newClause)) {
continue;
} else if(it.canDescend()) {
it.descend();
}
}
}
}
*/
/**
* A class intended for keeping track of possible constant values of a variable.
*
* Do I have to work with clauses? Or is it possible to simplify?
*
* OK, I don't think this class makes sense right now.
* If we map a variable to a constant, then we don't need to deal with alternatives.
* And if we want to mess around with expressions and satisfiability, then we can just
* work on the expression level, rather trying to destill possible constant assignments from the exprs
* (althought it might be useable for optimization)
*
* @author Claus Stadler <cstadler@informatik.uni-leipzig.de>
*
* @param <T>
*/
class ValueSet<T>
{
private Set<Set<T>> alternatives;
/**
* Example 1: Alternatives, or
* (a = x || a = y)
* -> ((x), (y))
*
* ... && (a = x || a = z)
* -> a = x
*
*
*
* Example 2: Negated alternatives
* (?a != y || ?a != z) -> no constraint derivable
* "x is either not an Animal or it is not a Person"
* ((!y), (!z))
*
*
* Example 3: Negative alternatives
* (?a != y && ?a != z)
* "x is neither an Animal nor a Person"
* -> neg = (!y, !z)
*
* Example 4: Mixed
* (?a = x || ?a = y || ?a != y || ?a != z)
*
*
* Example 5: Mixed
* (?a = v || ?a = w) && (?a != v && ?a != y)
* -> (?a = v && ?a != v && ?a != y) || (?a = w && ?a != v && ?a != y)
* -> (false) || (?a = w && ?a != v && ?a != y)
* pos = {w}
*
*
* So stating an equality
*
* @param values
*/
public void stateAlternatives(Set<T> values) {
}
}