Package de.fuberlin.wiwiss.d2rq.engine

Source Code of de.fuberlin.wiwiss.d2rq.engine.TransformFilterCNF$DistributiveLawApplyer

package de.fuberlin.wiwiss.d2rq.engine;

import com.hp.hpl.jena.sparql.algebra.Op;
import com.hp.hpl.jena.sparql.algebra.TransformCopy;
import com.hp.hpl.jena.sparql.algebra.op.OpFilter;
import com.hp.hpl.jena.sparql.expr.E_LogicalAnd;
import com.hp.hpl.jena.sparql.expr.E_LogicalNot;
import com.hp.hpl.jena.sparql.expr.E_LogicalOr;
import com.hp.hpl.jena.sparql.expr.Expr;
import com.hp.hpl.jena.sparql.expr.ExprAggregator;
import com.hp.hpl.jena.sparql.expr.ExprFunction0;
import com.hp.hpl.jena.sparql.expr.ExprFunction1;
import com.hp.hpl.jena.sparql.expr.ExprFunction2;
import com.hp.hpl.jena.sparql.expr.ExprFunction3;
import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
import com.hp.hpl.jena.sparql.expr.ExprList;
import com.hp.hpl.jena.sparql.expr.ExprNode;
import com.hp.hpl.jena.sparql.expr.ExprVar;
import com.hp.hpl.jena.sparql.expr.ExprVisitor;
import com.hp.hpl.jena.sparql.expr.NodeValue;

/**
* Checks if any {@link OpFilter} can be split into more
* parts by translating it to Conjunctive Normal Form (CNF).
*
* @author Herwig Leimer
* @author Richard Cyganiak (richard@cyganiak.de)
*/
public class TransformFilterCNF extends TransformCopy {
 
  public Op transform(OpFilter opFilter, Op subOp) {
    ExprList exprList = ExprList.splitConjunction(opFilter.getExprs());
    ExprList cnfExprList = ExprList.splitConjunction(
        TransformFilterCNF.translateFilterExpressionsToCNF(opFilter));
    if (cnfExprList.size() > exprList.size()) {
      return OpFilter.filter(cnfExprList, subOp);
    }
    return OpFilter.filter(exprList, subOp);
  }

  /**
   * Translates all expressions of a filter to the conjunctive normalform.
   * To get the conjunctive normalform of a term, first the law of DeMorgan and then
   * the Distributive-law will be applied 
   * @param opFilter - a Filter with some expressions
   * @return ExprList - every entry of the exprlist is in conjunctive normalform
   */
  public static ExprList translateFilterExpressionsToCNF(final OpFilter opFilter)
  {
    ExprList exprList, newExprList;
    OpFilter copiedOpFilter;
   
    newExprList = new ExprList()// contains the translated expressions
    exprList = opFilter.getExprs();
   
    // workaround to avoid deep copy from the expressions
    // because deep copy is not available in Q_UnaryNot.java
    copiedOpFilter = (OpFilter) OpFilter.filter(exprList, opFilter.getSubOp());
    exprList = copiedOpFilter.getExprs();
   
    // for every expression of the filter, apply first DeMorgan-law and then Distributive-law
    for (Expr expr: exprList) {
      if (expr instanceof ExprNode) { // only SPARQL expressions are handled (e.g. no RDQL SimpleNode)
              expr = applyDeMorganLaw(expr);       // !(a || b) will become !a && !b
              expr = applyDistributiveLaw(expr);    // a || (b && c) will become (a || b) && (a || c)
      }
          newExprList.add(expr);
        }
   
    // split ever expression that contains conjunctions
    // a term like (a > 3) && (b > 4) will become to the two terms: (a > 3), (b > 4)
    newExprList = ExprList.splitConjunction(newExprList);
   
    return newExprList;
  }
 
 
  /**
   * Method for appling the law of DeMorgan.
   * @param expr - root-node of the current expression-tree
   * @return Expr - the new expression
   */
  private static Expr applyDeMorganLaw(Expr expr)
  {
    DeMorganLawApplyer deMorganLawApplyer = new DeMorganLawApplyer();
   
    // copy expression to maintain the original one
    //    newExpr = expr.deepCopy();   
   
    // apply the rule
    expr.visit(deMorganLawApplyer);
    expr = deMorganLawApplyer.result();
   
    return expr;
  }
 
  /**
   * Method for appling the rules of the distributiv-law
   * @param expr - root-node of the current expression-tree
   * @return Expr - the new expression
   */
  private static Expr applyDistributiveLaw(Expr expr)
  {
    DistributiveLawApplyer distributiveLawApplyer = new DistributiveLawApplyer();
   
    // copy expression to maintain the original one
    //    newExpr = expr.deepCopy();   
   
    // apply the rule
    expr.visit(distributiveLawApplyer);
    expr = distributiveLawApplyer.result();
   
    return expr;
  }
  /**
   * Visitor for a filter-expression. Visits every expression-node of the expression-tree
   * and applies the DeMorgan-law: !(a || b) will become !a && !b
   *
   * @author Herwig Leimer
   *
   */
  public static class DeMorganLawApplyer implements ExprVisitor
  {
    private Expr resultExpr;
   
    /**
     * Constructor
     */
    public DeMorganLawApplyer()
    {   
    }

    public void finishVisit()
    {
    }

    public void startVisit()
    {
    }

    public void visit(NodeValue nv)
    {
      this.resultExpr = nv;
    }

    public void visit(ExprVar nv)
    {
      this.resultExpr = nv;
    }

    public void visit(ExprFunction0 func) {
      this.resultExpr = func;
    }

    public void visit(ExprFunction1 curExpr) {
      Expr subExpr, leftExpr, rightExpr;
      Expr newAndExpr;

      subExpr = (curExpr).getArg();
     
      if (curExpr instanceof E_LogicalNot)
      {
        // !!a ==> a
        if (subExpr instanceof E_LogicalNot) {
          this.resultExpr = ((ExprFunction1) subExpr).getArg();
        }
       
        // apply DeMorgan
        // !(a || b) ==> !a && !b
            // AndyL: don't change !(a && b) to !a || !b (no benefit!)
        else if (subExpr instanceof E_LogicalOr )
        {
          // step down
          leftExpr = ((ExprFunction2)subExpr).getArg1();
          leftExpr.visit(this);
          leftExpr = this.resultExpr;

          // step down
          rightExpr = ((ExprFunction2)subExpr).getArg2();
          rightExpr.visit(this);
          rightExpr = this.resultExpr;
         
         
          if (!(leftExpr instanceof E_LogicalNot))
          {
            // add not
            leftExpr = new E_LogicalNot(leftExpr)
          }else
          {
            // remove not
            leftExpr = ((E_LogicalNot)leftExpr).getArg();
          }
         
          if (!(rightExpr instanceof E_LogicalNot))
          {
            // add not
            rightExpr = new E_LogicalNot(rightExpr);
          }else
          {
            // remove not
            rightExpr = ((E_LogicalNot)rightExpr).getArg();
          }
         
//          // change operator
//          if (subExpr instanceof E_LogicalAnd)
//          {
//            newOrExpr = new E_LogicalOr(leftExpr, rightExpr);
//            this.resultExpr = newOrExpr;
//           
//          }else if (subExpr instanceof E_LogicalOr)
//          {
            newAndExpr = new E_LogicalAnd(leftExpr, rightExpr);
            this.resultExpr = newAndExpr;
//          }
       
        }else
        {
          this.resultExpr = curExpr;
        }
      }else
      {
        // step down
        subExpr.visit(this)
        this.resultExpr = curExpr;
      }
    }

    public void visit(ExprFunction2 curExpr) {
      Expr leftExpr, rightExpr;

      if (curExpr instanceof E_LogicalOr || curExpr instanceof E_LogicalAnd)
      {
        // step down
        leftExpr = ((ExprFunction2)curExpr).getArg1();
        leftExpr.visit(this);
        leftExpr = this.resultExpr;

        // step down
        rightExpr = ((ExprFunction2)curExpr).getArg2();
        rightExpr.visit(this);
        rightExpr = this.resultExpr;
       
        // create new And/Or with resultExpr
        if (curExpr instanceof E_LogicalOr)
        {
          this.resultExpr = new E_LogicalOr(leftExpr, rightExpr);
        }else if (curExpr instanceof E_LogicalAnd)
        {
          this.resultExpr = new E_LogicalAnd(leftExpr, rightExpr);
        }
             
      }else
      {
        this.resultExpr = curExpr;
      }
    }

    public void visit(ExprFunction3 func) {
      this.resultExpr = func;
    }

    public void visit(ExprFunctionN func) {
      this.resultExpr = func;
    }

    public void visit(ExprFunctionOp funcOp) {
      this.resultExpr = funcOp;
    }

    public void visit(ExprAggregator eAgg) {
      this.resultExpr = eAgg;
    }
   
    public Expr result()
      {
          return resultExpr;
      }
  }
  /**
   * Visitor for a filter-expression. Visits every expression-node of the expression-tree
   * and applies the Distributive-law: a || (b && c) will become (a || b) && (a || c)
   *
   * @author Herwig Leimer
   *
   */
  public static class DistributiveLawApplyer implements ExprVisitor
  {
    private Expr resultExpr;
   
    /**
     * Constructor
     */
    public DistributiveLawApplyer()
    {   
    }

    public void finishVisit()
    {
    }

    public void startVisit()
    {
    }

    public void visit(NodeValue nv)
    {
      this.resultExpr = nv;
    }

    public void visit(ExprVar nv)
    {
      this.resultExpr = nv;
    }

    public void visit(ExprFunction0 func) {
      this.resultExpr = func;
    }

    public void visit(ExprFunction1 curExpr) {
      Expr subExpr;
      if (curExpr instanceof E_LogicalNot)
      {
        subExpr = curExpr;
        // step down
        this.resultExpr = curExpr;
        ((ExprFunction1) subExpr).getArg().visit(this);
        this.resultExpr = new E_LogicalNot(this.resultExpr);
      } else {
        this.resultExpr = curExpr;
      }
    }

    public void visit(ExprFunction2 curExpr) {
      Expr leftExpr, rightExpr;
      Expr leftLeftExpr, rightLeftExpr, leftRightExpr, rightRightExpr;
      Expr newAndExpr, newOrExpr1, newOrExpr2;

      if (curExpr instanceof E_LogicalOr || curExpr instanceof E_LogicalAnd)
      {
        // step down
        leftExpr = curExpr.getArg1();
        leftExpr.visit(this);
        leftExpr = this.resultExpr;

        // step down
        rightExpr = curExpr.getArg2();
        rightExpr.visit(this);
        rightExpr = this.resultExpr;
       
        if (curExpr instanceof E_LogicalOr)
        {
          if (!(leftExpr instanceof E_LogicalAnd) && !(rightExpr instanceof E_LogicalAnd))
          {
            // no distributive law - normal or
            this.resultExpr = new E_LogicalOr(leftExpr, rightExpr);
          }else
          {
            // criterion for distributive law - first OR, then AND
           
            if (leftExpr instanceof E_LogicalAnd)
            {
              leftLeftExpr = ((E_LogicalAnd)leftExpr).getArg1();
              rightLeftExpr = ((E_LogicalAnd)leftExpr).getArg2();
             
              // OR AND will become to AND OR OR
              newOrExpr1 = new E_LogicalOr(leftLeftExpr, rightExpr);
              newOrExpr2 = new E_LogicalOr(rightLeftExpr, rightExpr);
              newAndExpr = new E_LogicalAnd(newOrExpr1, newOrExpr2);
             
              this.resultExpr = newAndExpr;
              // apply for subexpression again
              newAndExpr.visit(this);
            }
           
            if (rightExpr instanceof E_LogicalAnd)
            {
              leftRightExpr = ((E_LogicalAnd)rightExpr).getArg1();
              rightRightExpr = ((E_LogicalAnd)rightExpr).getArg2();
           
              // OR AND will become to AND OR OR
              newOrExpr1 = new E_LogicalOr(leftExpr, leftRightExpr);
              newOrExpr2 = new E_LogicalOr(leftExpr, rightRightExpr);
              newAndExpr = new E_LogicalAnd(newOrExpr1, newOrExpr2);
           
              this.resultExpr = newAndExpr;
              // apply for subexpression again
              newAndExpr.visit(this);
            }
          }         
        }else
        {
          // E_LogicalAnd
          this.resultExpr = new E_LogicalAnd(leftExpr, rightExpr);
        }       
      }else
      {
        this.resultExpr = curExpr;
      }
    }

    public void visit(ExprFunction3 func) {
      this.resultExpr = func;
    }

    public void visit(ExprFunctionN func) {
      this.resultExpr = func;
    }

    public void visit(ExprFunctionOp funcOp) {
      this.resultExpr = funcOp;
    }

    public void visit(ExprAggregator eAgg) {
      this.resultExpr = eAgg;
    }

    public Expr result()
    {
      return resultExpr;
    }
  }
}
TOP

Related Classes of de.fuberlin.wiwiss.d2rq.engine.TransformFilterCNF$DistributiveLawApplyer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.