package org.aksw.sparqlify.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; interface CollectionFactory<T> { Collection<T> newCollection(); } class CollectionFactoryArrayList<T> implements CollectionFactory<T> { @Override public ArrayList<T> newCollection() { return new ArrayList<T>(); } } public class CnfTransformer<T> { private ExprAccessor<T> accessor; public CnfTransformer(ExprAccessor<T> accessor) { this.accessor = accessor; } public T eval(T expr) { T result = eval(expr, accessor); return result; } public static <T> T eval(T expr, ExprAccessor<T> accessor) { T result; if(accessor.isLogicalNot(expr)) { T child = accessor.getArg(expr); T newExpr; if (accessor.isLogicalAnd(child)) { newExpr = accessor.createLogicalOr( eval(accessor.createLogicalNot(accessor.getArg1(child)), accessor), eval(accessor.createLogicalNot(accessor.getArg2(child)), accessor)); } else if (accessor.isLogicalOr(child)) { newExpr = accessor.createLogicalAnd( eval(accessor.createLogicalNot(accessor.getArg(child)), accessor), eval(accessor.createLogicalNot(accessor.getArg(child)), accessor)); } else if (accessor.isLogicalNot(child)) { newExpr = eval(accessor.getArg(child), accessor); } else { return expr; } result = eval(newExpr, accessor); } else if (accessor.isLogicalAnd(expr)) { //return expr; //return eval(expr); result = accessor.createLogicalAnd( eval(accessor.getArg1(expr), accessor), eval(accessor.getArg2(expr), accessor)); } else if (accessor.isLogicalOr(expr)) { T aa = eval(accessor.getArg1(expr), accessor); T bb = eval(accessor.getArg2(expr), accessor); // If at least one of the expr's argument is a logical and, // then it will be assigned to a T a = null; T b = null; if (accessor.isLogicalAnd(aa)) { a = aa; b = bb; } else if(accessor.isLogicalAnd(bb)) { a = bb; b = aa; } if(a == null) { result = accessor.createLogicalOr(aa, bb); } else { result = accessor.createLogicalAnd( eval(accessor.createLogicalOr(accessor.getArg1(a), b), accessor), eval(accessor.createLogicalOr(accessor.getArg2(a), b), accessor)); } } else { result = expr; } // else if (expr instanceof E_NotEquals) { // Normalize (a != b) to !(a = b) --- this makes it easier to find "a and !a" cases // return new E_LogicalNot(eval(new E_Equals(expr.getArg(1), expr.getArg(2)))); // } return result; } public static <T> List<Collection<T>> toCnf(T expr, ExprAccessor<T> accessor) { List<Collection<T>> result = toCnf(Collections.singleton(expr), accessor); return result; } public static <T> List<Collection<T>> toCnf(Iterable<T> exprs, ExprAccessor<T> accessor) { List<Collection<T>> result = new ArrayList<Collection<T>>(); CollectionFactory<T> clauseFactory = new CollectionFactoryArrayList<T>(); for(T expr : exprs) { T tmp = eval(expr, accessor); collectAnd(tmp, result, accessor, clauseFactory); } return result; } /** * This method only words if the input expressions are in DNF, * otherwise you will likely get junk back. * * @param exprs * @return */ public static <T> List<Collection<T>> cnfToClauses(Iterable<T> exprs, ExprAccessor<T> accessor) { List<Collection<T>> result = new ArrayList<Collection<T>>(); CollectionFactory<T> clauseFactory = new CollectionFactoryArrayList<T>(); for(T expr : exprs) { collectAnd(expr, result, accessor, clauseFactory); } return result; } public static <T> void collectAnd(T expr, Collection<Collection<T>> clauses, ExprAccessor<T> accessor, CollectionFactory<T> clauseFactory) { if(accessor.isLogicalAnd(expr)) { collectAnd(accessor.getArg1(expr), clauses, accessor, clauseFactory); collectAnd(accessor.getArg2(expr), clauses, accessor, clauseFactory); } else if(accessor.isLogicalOr(expr)) { //List<Expr> ors = new ArrayList<Expr>(); Collection<T> ors = clauseFactory.newCollection(); collectOr(expr, ors, accessor); clauses.add(ors); } else { Collection<T> ors = clauseFactory.newCollection(); ors.add(expr); clauses.add(ors); } } public static <T> void collectOr(T expr, Collection<T> clause, ExprAccessor<T> accessor) { if(accessor.isLogicalOr(expr)) { collectOr(accessor.getArg1(expr), clause, accessor); collectOr(accessor.getArg2(expr), clause, accessor); } else { clause.add(expr); } } }