/* * Copyright 2009 DuraSpace, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mulgara.resolver.spi; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; import org.mulgara.query.Constraint; import org.mulgara.query.ConstraintExpression; import org.mulgara.query.ConstraintConjunction; import org.mulgara.query.ConstraintDisjunction; import org.mulgara.query.ConstraintFilter; /** * A transformer that works on the basis of expanding a product of sums into a sum of products. * This is needed because our disjunctions (sums) are very inefficient, particularly for searching. * Performs the following transforms: * A and (B or C) -> (A and B) or (A and C) * FILTER(A or B, F) -> FILTER(A, F) or FILTER(B, F) * TODO: * A and ((B or C) - D) -> (A and (B - D)) or (A and (C - D)) * A - (B or C) -> (A - B) - C, iff B and C share all variables * * @created August 7, 2009 * @author Paula Gearon * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a> */ public class SumOfProductExpansionTransformer extends AbstractSymbolicTransformer { /** Logger */ @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(SumOfProductExpansionTransformer.class.getName()); @Override public ConstraintExpression transformExpression(SymbolicTransformationContext context, ConstraintExpression expr) throws SymbolicTransformationException { // This is the main case. if (expr instanceof ConstraintConjunction) { return transformConjunction(context, (ConstraintConjunction)expr); } // all else go through the default handling return super.transformExpression(context, expr); } protected ConstraintExpression transformConjunction(SymbolicTransformationContext context, ConstraintConjunction expr) throws SymbolicTransformationException { List<ConstraintExpression> args = expr.getElements(); for (int i = 0; i < args.size(); i++) { ConstraintExpression arg = args.get(i); // depth first ConstraintExpression tx = transformExpression(context, arg); if (tx != arg) { // there was a change, so reset and start again List<ConstraintExpression> newArgs = new ArrayList<ConstraintExpression>(args); newArgs.set(i, tx); return new ConstraintConjunction(newArgs); } // test for expansion if (arg instanceof ConstraintDisjunction) { return expandConstraint((ConstraintDisjunction)arg, args, i); } // test filtered constraints for expansion if (arg instanceof ConstraintFilter) { ConstraintFilter filtered = (ConstraintFilter)arg; ConstraintExpression innerArg = filtered.getUnfilteredConstraint(); if (innerArg instanceof ConstraintDisjunction) { return new ConstraintFilter(expandConstraint((ConstraintDisjunction)innerArg, args, i), filtered.getFilter()); } } } // no expandable terms found return expr; } /** * Creates a new ConstraintDisjunction of conjunctions with one fewer disjunctive term. * @param arg The disjunction to be expanded into the outer conjunction. * @param outerArgs The arguments of the parent expression to be distributed into. * @param argOffset The position of the argument to be replaced in the outerArgs * @return */ private ConstraintDisjunction expandConstraint(ConstraintDisjunction arg, List<ConstraintExpression> outerArgs, int argOffset) { // need to expand by duplicating the conjunction for each element in the disjunction List<ConstraintExpression> disjArgs = arg.getElements(); // accumulate the arguments to the new parent disjunction List<ConstraintExpression> expandedDisjArgs = new ArrayList<ConstraintExpression>(); for (ConstraintExpression disjArg: disjArgs) { // copy the original arguments List<ConstraintExpression> conjArgs = new ArrayList<ConstraintExpression>(outerArgs); // replace the disjunction element with one of the arguments from the disjunction conjArgs.set(argOffset, disjArg); // create a new conjunction with these modified arguments expandedDisjArgs.add(new ConstraintConjunction(conjArgs)); } // check that the distibution is the same size assert expandedDisjArgs.size() == disjArgs.size(); return new ConstraintDisjunction(expandedDisjArgs); } @Override protected ConstraintExpression transformConstraint(SymbolicTransformationContext context, Constraint c) throws SymbolicTransformationException { return c; } }