Package org.jrdf.query.execute

Source Code of org.jrdf.query.execute.ExpressionSimplifierImpl

/*
* $Header$
* $Revision: 982 $
* $Date: 2006-12-08 18:42:51 +1000 (Fri, 08 Dec 2006) $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003-2009 The JRDF Project.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution, if
*    any, must include the following acknowlegement:
*       "This product includes software developed by the
*        the JRDF Project (http://jrdf.sf.net/)."
*    Alternately, this acknowlegement may appear in the software itself,
*    if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The JRDF Project" and "JRDF" must not be used to endorse
*    or promote products derived from this software without prior written
*    permission. For written permission, please contact
*    newmana@users.sourceforge.net.
*
* 5. Products derived from this software may not be called "JRDF"
*    nor may "JRDF" appear in their names without prior written
*    permission of the JRDF Project.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the JRDF Project.  For more
* information on JRDF, please see <http://jrdf.sourceforge.net/>.
*
*/

package org.jrdf.query.execute;

import org.jrdf.graph.AnyNode;
import org.jrdf.graph.AnyObjectNode;
import org.jrdf.graph.AnyPredicateNode;
import org.jrdf.graph.AnySubjectNode;
import org.jrdf.graph.Node;
import static org.jrdf.query.execute.ExpressionComparatorImpl.EXPRESSION_COMPARATOR;
import org.jrdf.query.expression.Ask;
import org.jrdf.query.expression.BoundOperator;
import org.jrdf.query.expression.Conjunction;
import org.jrdf.query.expression.EmptyConstraint;
import static org.jrdf.query.expression.EmptyConstraint.EMPTY_CONSTRAINT;
import org.jrdf.query.expression.Expression;
import org.jrdf.query.expression.ExpressionVisitorAdapter;
import org.jrdf.query.expression.Filter;
import org.jrdf.query.expression.LangOperator;
import org.jrdf.query.expression.Optional;
import org.jrdf.query.expression.Projection;
import org.jrdf.query.expression.SingleConstraint;
import org.jrdf.query.expression.SingleValue;
import org.jrdf.query.expression.StrOperator;
import org.jrdf.query.expression.Union;
import org.jrdf.query.expression.logic.EqualsExpression;
import org.jrdf.query.expression.logic.FalseExpression;
import static org.jrdf.query.expression.logic.FalseExpression.FALSE_EXPRESSION;
import org.jrdf.query.expression.logic.LessThanExpression;
import org.jrdf.query.expression.logic.LogicAndExpression;
import org.jrdf.query.expression.logic.LogicExpression;
import org.jrdf.query.expression.logic.LogicNotExpression;
import org.jrdf.query.expression.logic.LogicOrExpression;
import org.jrdf.query.expression.logic.NEqualsExpression;
import org.jrdf.query.expression.logic.TrueExpression;
import static org.jrdf.query.expression.logic.TrueExpression.TRUE_EXPRESSION;
import org.jrdf.query.relation.Attribute;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* @author Yuan-Fang Li
* @version $Id:$
*/
public class ExpressionSimplifierImpl extends ExpressionVisitorAdapter<Void>
    implements ExpressionSimplifier<Void> {
    private Expression expression;
    private Set<Attribute> declaredVariables;
    private Map<Attribute, Attribute> variableMap;
    private Map<Attribute, Node> attributeValues;

    public ExpressionSimplifierImpl() {
        this.attributeValues = new HashMap<Attribute, Node>();
        this.variableMap = new HashMap<Attribute, Attribute>();
        this.declaredVariables = new LinkedHashSet<Attribute>();
    }

    public ExpressionSimplifierImpl(Map<Attribute, Node> newAttributeValues,
        Map<Attribute, Attribute> newVariableMap, Set<Attribute> newDeclaredVariables) {
        this.attributeValues = newAttributeValues;
        this.variableMap = newVariableMap;
        this.declaredVariables = newDeclaredVariables;
    }

    public Expression getExpression() {
        return expression;
    }

    public Void visitProjection(Projection projection) {
        declaredVariables = projection.getAttributes();
        Expression next = getNext(projection.getNextExpression());
        projection.setNextExpression(next);
        expression = projection;
        return null;
    }

    public Void visitConjunction(Conjunction conjunction) {
        final Expression lhs = getNext(conjunction.getLhs());
        final Expression rhs = getNext(conjunction.getRhs());
        if (lhs == null && rhs == null) {
            expression = null;
        } else if (lhs == null) {
            expression = rhs;
        } else if (rhs == null) {
            expression = lhs;
        } else {
            expression = constructNewConjunction(lhs, rhs);
        }
        return null;
    }

    private Expression constructNewConjunction(Expression lhs, Expression rhs) {
        Expression tmpExpression = constructFilteredConjunction(lhs, rhs);
        if (tmpExpression == null) {
            tmpExpression = constructUnionedConjunction(lhs, rhs);
            if (tmpExpression == null) {
                if (EXPRESSION_COMPARATOR.compare(lhs, rhs) <= 0) {
                    tmpExpression = new Conjunction(lhs, rhs);
                } else {
                    tmpExpression = new Conjunction(rhs, lhs);
                }
            }
        }
        return tmpExpression;
    }

    private Expression constructFilteredConjunction(Expression lhs, Expression rhs) {
        Expression tmpExpression = null;
        if (lhs instanceof Filter && rhs instanceof Filter) {
            Expression llhs = ((Filter) lhs).getLhs();
            Expression lrhs = ((Filter) rhs).getLhs();
            tmpExpression = new Conjunction(llhs, lrhs);
            LogicExpression andExp = new LogicAndExpression(((Filter) lhs).getRhs(),
                ((Filter) rhs).getRhs());
            tmpExpression = new Filter(tmpExpression, andExp);
        } else if (lhs instanceof Filter) {
            tmpExpression = constructConjFilter((Filter) lhs, rhs);
        } else if (rhs instanceof Filter) {
            tmpExpression = constructConjFilter((Filter) rhs, lhs);
        }
        return getNext(tmpExpression);
    }

    private Expression constructConjFilter(Filter lhs, Expression rhs) {
        Expression result;
        Expression llhs = lhs.getLhs();
        result = new Conjunction(llhs, rhs);
        result = new Filter(result, lhs.getRhs());
        return result;
    }

    private Expression constructUnionedConjunction(Expression lhs, Expression rhs) {
        Expression tmpExpression = null;
        if (lhs instanceof Union) {
            tmpExpression = distributeConjunctionWithUnion((Union) lhs, rhs);
        } else if (rhs instanceof Union) {
            tmpExpression = distributeConjunctionWithUnion((Union) rhs, lhs);
        }
        return getNext(tmpExpression);
    }

    private Expression distributeConjunctionWithUnion(Union lhs, Expression rhs) {
        Expression uLhs = lhs.getLhs();
        Expression uRhs = lhs.getRhs();
        Expression newConj1 = getNext(new Conjunction(rhs, uLhs));
        Expression newConj2 = getNext(new Conjunction(rhs, uRhs));
        return getNext(new Union(newConj1, newConj2));
    }

    public Void visitUnion(Union conjunction) {
        final Expression lhs = getNext(conjunction.getLhs());
        final Expression rhs = getNext(conjunction.getRhs());
        if (EXPRESSION_COMPARATOR.compare(lhs, rhs) <= 0) {
            expression = new Union(lhs, rhs);
        } else {
            expression = new Union(rhs, lhs);
        }
        return null;
    }

    public Void visitOptional(Optional optional) {
        Expression lhsExp = optional.getLhs();
        lhsExp = (lhsExp == null) ? EMPTY_CONSTRAINT : lhsExp;
        Expression lhs = getNext(lhsExp);
        Expression rhsExp = optional.getRhs();
        rhsExp = (rhsExp == null) ? EMPTY_CONSTRAINT : rhsExp;
        Expression rhs = getNext(rhsExp);
        expression = new Optional(lhs, rhs);
        return null;
    }

    public Void visitFilter(Filter filter) {
        LogicExpression logicExpression = (LogicExpression) getNext(filter.getRhs());
        expression = getNext(filter.getLhs());
        if (logicExpression != null) {
            expression = new Filter(expression, logicExpression);
        }
        return null;
    }

    public Void visitLogicAnd(LogicAndExpression andExpression) {
        Expression lhs = getNext(andExpression.getLhs());
        Expression rhs = getNext(andExpression.getRhs());
        if (lhs == null && rhs == null) {
            expression = null;
        } else if (lhs == null) {
            expression = rhs;
        } else if (rhs == null) {
            expression = lhs;
        } else {
            expression = andExpression;
        }
        return null;
    }

    public Void visitLogicOr(LogicOrExpression orExpression) {
        Expression lhs = getNext(orExpression.getLhs());
        Expression rhs = getNext(orExpression.getRhs());
        if (lhs == null && rhs == null) {
            expression = null;
        } else if (lhs == null) {
            expression = rhs;
        } else if (rhs == null) {
            expression = lhs;
        } else {
            expression = orExpression;
        }
        return null;
    }

    public Void visitEqualsExpression(EqualsExpression equalsExpression) {
        Expression lhs = getNext(equalsExpression.getLhs());
        Expression rhs = getNext(equalsExpression.getRhs());
        final List<Expression> pair = reorderPairs(lhs, rhs);
        boolean changed = equateExpressions(lhs, rhs);
        if (!changed) {
            changed = equateAVOs(pair.get(0).getValue(), pair.get(1).getValue());
            if (changed) {
                expression = null;
            } else {
                lhs = pair.get(0);
                rhs = pair.get(1);
                expression = new EqualsExpression(lhs, rhs);
            }
        }
        return null;
    }

    public Void visitTrue(TrueExpression trueExp) {
        expression = trueExp;
        return null;
    }

    public Void visitFalse(FalseExpression falseExp) {
        expression = falseExp;
        return null;
    }

    private boolean equateExpressions(Expression lhs, Expression rhs) {
        boolean changed = false;
        if (isTrueExp(lhs) || isFalseExp(lhs)) {
            equateRhsExp(lhs, rhs);
            changed = true;
        } else if (isTrueExp(rhs) || isFalseExp(rhs)) {
            equateRhsExp(rhs, lhs);
            changed = true;
        }
        return changed;
    }

    private void equateRhsExp(Expression lhs, Expression rhs) {
        if (isTrueExp(lhs)) {
            expression = rhs;
        } else if (isFalseExp(lhs)) {
            if (isTrueExp(rhs)) {
                expression = FALSE_EXPRESSION;
            } else if (isFalseExp(rhs)) {
                expression = TRUE_EXPRESSION;
            } else {
                expression = new LogicNotExpression((LogicExpression) rhs);
            }
        }
    }

    private boolean isTrueExp(Expression exp) {
        return TRUE_EXPRESSION.equals(exp);
    }

    private boolean isFalseExp(Expression exp) {
        return FALSE_EXPRESSION.equals(exp);
    }

    private List<Expression> reorderPairs(Expression lhs, Expression rhs) {
        List<Expression> result = new ArrayList<Expression>(2);
        final int lhsSize = lhs.size();
        final int rhsSize = rhs.size();
        if (lhsSize >= rhsSize) {
            result.add(0, lhs);
            result.add(1, rhs);
        } else {
            result.add(0, rhs);
            result.add(1, lhs);
        }
        return result;
    }

    private boolean equateAVOs(Map<Attribute, Node> lhs, Map<Attribute, Node> rhs) {
        Attribute attribute = lhs.keySet().iterator().next();
        Node lvo = lhs.get(attribute);
        Node rvo = rhs.get(attribute);
        if (isAnyNode(lvo)) {
            if (rvo != null) {
                updateAttributeValue(attribute, lvo, rvo);
            } else {
                // assuming a variable now
                updateVariableMap(rhs, attribute);
            }
            return true;
        }
        return false;
    }

    private void updateAttributeValue(Attribute attribute, Node lvo, Node rvo) {
        final Attribute value = variableMap.get(attribute);
        attributeValues.put(attribute, rvo);
        if (value != null) {
            attributeValues.put(value, rvo);
        }
    }

    private void updateVariableMap(Map<Attribute, Node> rhs, Attribute attribute) {
        Attribute newAttr = rhs.keySet().iterator().next();
        Attribute key, value;
        if (declaredVariables.contains(attribute)) {
            key = newAttr;
            value = attribute;
        } else {
            key = attribute;
            value = newAttr;
        }
        Attribute fixPoint = variableMap.get(value);
        if (fixPoint == null) {
            fixPoint = value;
        }
        variableMap.put(key, fixPoint);
    }

    private LinkedHashMap<Attribute, Node> updateAVPVariables(Map<Attribute, Node> avp) {
        LinkedHashMap<Attribute, Node> newAVP = new LinkedHashMap<Attribute, Node>();
        for (Map.Entry<Attribute, Node> entry : avp.entrySet()) {
            final Attribute newAttribute = variableMap.get(entry.getKey());
            if (newAttribute != null) {
                newAVP.put(newAttribute, entry.getValue());
            } else {
                newAVP.put(entry.getKey(), entry.getValue());
            }
        }
        return newAVP;
    }

    private boolean isAnyNode(org.jrdf.graph.Node node) {
        return node instanceof AnySubjectNode || node instanceof AnyPredicateNode ||
            node instanceof AnyObjectNode || node instanceof AnyNode;
    }

    public Void visitConstraint(SingleConstraint constraint) {
        LinkedHashMap<Attribute, Node> avo = updateAVO(constraint.getAvo(null));
        expression = new SingleConstraint(avo);
        return null;
    }

    public Void visitEmptyConstraint(EmptyConstraint constraint) {
        expression = constraint;
        return null;
    }

    // Skip logical not now.
    public Void visitLogicNot(LogicNotExpression notExpression) {
//        LogicExpression exp = (LogicExpression) getNext(notExpression.getExpression());
//        expression = new LogicNotExpression(exp);
        expression = notExpression;
        return null;
    }

    public Void visitBound(BoundOperator bound) {
        expression = bound;
        return null;
    }

    public Void visitLang(LangOperator lang) {
        LinkedHashMap<Attribute, Node> avo = updateAVPVariables(lang.getValue());
        expression = new LangOperator(avo);
        return null;
    }

    public Void visitStr(StrOperator str) {
        LinkedHashMap<Attribute, Node> avo = updateAVPVariables(str.getValue());
        expression = new StrOperator(avo);
        return null;
    }

    public Void visitSingleValue(SingleValue value) {
        LinkedHashMap<Attribute, Node> avo = updateAVPVariables(value.getValue());
        expression = new SingleValue(avo);
        return null;
    }

    private LinkedHashMap<Attribute, Node> updateAVO(Map<Attribute, Node> oldAvo) {
        LinkedHashMap<Attribute, Node> avo = updateAVPVariables(oldAvo);
        for (Map.Entry<Attribute, Node> entry : avo.entrySet()) {
            if (attributeValues.get(entry.getKey()) != null) {
                avo.put(entry.getKey(), attributeValues.get(entry.getKey()));
            }
        }
        return avo;
    }

    public Void visitLessThanExpression(LessThanExpression lessThanExpression) {
        Expression lhs = getNext(lessThanExpression.getLhs());
        Expression rhs = getNext(lessThanExpression.getRhs());
        expression = new LessThanExpression(lhs, rhs);
        return null;
    }

    public Void visitNEqualsExpression(NEqualsExpression nEqualsExpression) {
        Expression lhs = getNext(nEqualsExpression.getLhs());
        Expression rhs = getNext(nEqualsExpression.getRhs());
        expression = new NEqualsExpression(lhs, rhs);
        return null;
    }

    public Void visitAsk(Ask ask) {
        Expression next = getNext(ask.getNextExpression());
        ask.setNextExpression(next);
        expression = ask;
        return null;
    }

    public boolean parseAgain() {
        return !variableMap.isEmpty();
    }

    private Expression getNext(Expression tmpExpression) {
        if (tmpExpression == null) {
            return null;
        }
        tmpExpression.accept(this);
        return expression;
    }
}
TOP

Related Classes of org.jrdf.query.execute.ExpressionSimplifierImpl

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.