Author: mickw
Date: 2006-05-16 13:18:47 +0200 (Tue, 16 May 2006)
New Revision: 2924

Added:
   trunk/src/java/no/schibstedsok/front/searchportal/query/parser/rot/
   
trunk/src/java/no/schibstedsok/front/searchportal/query/parser/rot/AlternationRotation.java
Log:
SEARCH-439 work-in-progress


Added: 
trunk/src/java/no/schibstedsok/front/searchportal/query/parser/rot/AlternationRotation.java
===================================================================
--- 
trunk/src/java/no/schibstedsok/front/searchportal/query/parser/rot/AlternationRotation.java
                         (rev 0)
+++ 
trunk/src/java/no/schibstedsok/front/searchportal/query/parser/rot/AlternationRotation.java
 2006-05-16 11:18:47 UTC (rev 2924)
@@ -0,0 +1,485 @@
+/* Copyright (2005-2006) Schibsted Søk AS
+ *
+ * AlternationRotation.java
+ *
+ * Created on 4 March 2006, 11:51
+ *
+ */
+
+package no.schibstedsok.front.searchportal.query.parser.rot;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import no.schibstedsok.common.ioc.BaseContext;
+import no.schibstedsok.front.searchportal.query.AndClause;
+import no.schibstedsok.front.searchportal.query.Clause;
+import no.schibstedsok.front.searchportal.query.DefaultOperatorClause;
+import no.schibstedsok.front.searchportal.query.LeafClause;
+import no.schibstedsok.front.searchportal.query.OperationClause;
+import no.schibstedsok.front.searchportal.query.OrClause;
+import no.schibstedsok.front.searchportal.query.XorClause;
+import 
no.schibstedsok.front.searchportal.query.parser.AbstractReflectionVisitor;
+import no.schibstedsok.front.searchportal.query.parser.QueryParser;
+import org.apache.log4j.Logger;
+
+/**
+ * @version $Id$
+ * @author <a href="mailto:[EMAIL PROTECTED]">Michael Semb Wever</a>
+ */
+public final class AlternationRotation {
+
+    public interface Context extends BaseContext, QueryParser.Context {  }
+
+    // Constants -----------------------------------------------------
+    private static final Logger LOG = 
Logger.getLogger(AlternationRotation.class);
+
+    // Attributes ----------------------------------------------------
+
+    private final Context context;
+    private final ParentFinder parentFinder = new ParentFinder();
+
+    /** mappings from the newly rotated clause to the same original clause **/
+    private final Map<OperationClause,OperationClause> originalFromNew = new 
HashMap<OperationClause,OperationClause>();
+    /** mappings from the original clause to the same newly rotated clause **/
+    private final Map<OperationClause,OperationClause> newFromOriginal = new 
HashMap<OperationClause,OperationClause>();
+    /** mappings from the newly rotated clause to the same unrotated clause **/
+    private final Map<OperationClause,OperationClause> beforeRotationFromNew = 
new HashMap<OperationClause,OperationClause>();
+    /** mappings from the original to the unrotated clause */
+    private final Map<OperationClause,OperationClause> 
beforeRotationFromOriginal = new HashMap<OperationClause,OperationClause>();
+
+    // Static --------------------------------------------------------
+
+    // Constructors --------------------------------------------------
+
+    /**
+     * Creates a new instance of AlternationRotation
+     */
+    public AlternationRotation(final Context cxt) {
+        context = cxt;
+    }
+
+    // Public --------------------------------------------------------
+
+    public Clause createRotations(final Clause originalRoot) {
+        // find forests (subtrees) of AndClauses and OrClauses.
+        if(originalRoot instanceof OperationClause){
+            OperationClause root = (OperationClause) originalRoot;
+            for(OperationClause clause : new 
ForestFinder().findForestRoots(root)){
+
+                final LinkedList<? extends OperationClause> rotations = clause 
instanceof AndClause
+                         ? createRotationsFor(AndClause.class, (AndClause) 
clause)
+                         : createRotationsFor(OrClause.class, (OrClause) 
clause);
+                final XorClause result = createXorClause(clause, rotations);
+                root = replaceDescendant(clause.getClass(), root, result, 
clause);
+            }
+            return root;
+        }else{
+            return originalRoot;
+        }
+
+    }
+
+    // Z implementation ----------------------------------------------
+
+    // Y overrides ---------------------------------------------------
+
+    // Package protected ---------------------------------------------
+
+    // Protected -----------------------------------------------------
+
+    // Private -------------------------------------------------------
+
+    private <T extends OperationClause> LinkedList<T> createRotationsFor(final 
Class<T> rotateFor, final T oForestRoot) {
+
+        LOG.debug("createRotationsFor(" + rotateFor.getSimpleName() + ", " + 
oForestRoot + ")");
+
+        // store this right-leaning branch for later comparason.
+        final List<T> origBranch = new ArrayList<T>();
+        for (T oC = oForestRoot; rightOpChild(rotateFor, oC) != null; oC = 
rightOpChild(rotateFor, oC)) {
+
+            // add to branch
+            origBranch.add(oC);
+            // add to the state-memory maps (creating initial map state, 
simple self pointing mappings)
+            originalFromNew.put(oC,oC);
+            beforeRotationFromNew.put(oC,oC);
+            beforeRotationFromOriginal.put(oC,oC);
+        }
+
+        // the size of the original right-leaning branch is also the number of 
alternations
+        final LinkedList<T> alternations = new LinkedList<T>();
+        // and the first nAlternation is the original branch
+        alternations.addFirst(oForestRoot);
+
+
+
+        // oIterate backwards from the right-most child (of type rotateFor) on 
the branch
+        final LinkedList<T> origBranchLL = new LinkedList<T>(origBranch);
+        for (T oIterate = origBranchLL.removeLast(); origBranchLL.size() > 1; 
oIterate = origBranchLL.removeLast()) {
+
+            // clear mappings
+            beforeRotationFromOriginal.clear();
+            for (Entry<OperationClause,OperationClause> entry : 
beforeRotationFromNew.entrySet()) {
+
+                // reverse key to values in each entry
+                
beforeRotationFromOriginal.put(originalFromNew.get(entry.getValue()), 
entry.getKey());
+            }
+            originalFromNew.clear();
+            newFromOriginal.clear();
+            beforeRotationFromNew.clear();
+
+            // find the right-most parent of iteration clause
+            final T rLastestForestRoot = (T) 
beforeRotationFromOriginal.get(oForestRoot);
+            T rBottom = (T) beforeRotationFromOriginal.get(oIterate);
+            while(rBottom == leftChild(parent(rLastestForestRoot, rBottom))){
+                rBottom = parent(rLastestForestRoot, rBottom);
+            }
+
+            // from 'rBottom' move upwards to the left,
+            //  continue repeating if next parent does not have parent to the 
right
+            T rTop = rBottom;
+            while(parent(rLastestForestRoot, rTop) == 
leftChild(parent(rLastestForestRoot, parent(rLastestForestRoot, rTop)))){
+                rTop = parent(rLastestForestRoot, rTop);
+            }
+
+            // we can rotate these now
+            final T nAlternation = rotate(rotateFor, oForestRoot, oIterate, 
rTop, rBottom);
+            alternations.addLast(nAlternation);
+        }
+
+        return alternations;
+    }
+
+
+    private <T extends OperationClause> T rotate(
+            final Class<T> rotateFor,
+            final T oForestRoot, // from original
+            final T oIterate,  // from original
+            final T rTop,  // from last rotation
+            final T rBottom) { // from last rotation
+
+        LOG.debug("rotate(" + oForestRoot + ", " + oIterate + ", " + rTop + ", 
" + rBottom + ")");
+
+        // RIGHT-LEANING-LOWER BRANCH ROTATION
+        LOG.debug("--- RIGHT-LEANING-LOWER BRANCH ROTATION ---");
+        // re-construct the branch starting at the oIterate
+        // the orpan must be from the newly rotated branch. (not the original 
or the last rotated branch).
+        // the first nOrphan is the exception because it is always a leaf 
that's free to re-use.
+        Clause nOrphan = leftChild(beforeRotationFromOriginal.get(oIterate));
+
+        T oC = parent(oForestRoot, oIterate);
+        do{
+            oC = parent(oForestRoot, oC);
+            LOG.debug(" orpan--> " + nOrphan);
+            LOG.debug(" c--> " + oC);
+            // oC is actually from the original branch.
+            //  But it doesn't matter because the left child is a leaf that's 
free to re-use.
+            nOrphan = createOperatorClause(rotateFor, leftChild(oC), nOrphan, 
oC);
+            LOG.debug("  result--> " + nOrphan);
+
+        }while(beforeRotationFromOriginal.get(oC) != rTop); // we have just 
rotated the rTop clause. getthefuckout.
+
+
+        // LEFT-LEANING-UPPER-BRANCH ROTATION
+        //  rotate what's now between the nOrphan and rBottom
+        LOG.debug("--- LEFT-LEANING-UPPER-BRANCH ROTATION ---");
+        oC = rightOpChild(rotateFor, (T)originalFromNew.get(nOrphan));
+        // first find the first right child that's not yet been orphaned.
+        while (newFromOriginal.get(oC) == null /*orphanage.contains( 
newFromOriginal.get(oC))*/) {
+            oC = rightOpChild(rotateFor, oC);
+        }
+
+        // re-construct the left-leaning tail branch
+        do{
+            oC = rightOpChild(rotateFor, oC);
+            LOG.debug(" orphan--> " + nOrphan);
+            LOG.debug(" c--> " + oC);
+            // oC is actually from the original branch.
+            final T rC = (T) beforeRotationFromOriginal.get(oC);
+            nOrphan = createOperatorClause(rotateFor, nOrphan, rightChild(rC), 
rC);
+            LOG.debug("  result--> " + nOrphan);
+
+        }while(beforeRotationFromOriginal.get(oC) != rBottom); // we have just 
rotated the rBottom. getthefuckout.
+
+
+        // ORIGINAL TREE ROOT ROTATION
+        LOG.debug("--- ORIGINAL TREE ROOT ROTATION ---");
+        // keep rotating above the centre of rotation
+            // loop rebuilding the tree, only replacing old instances with new 
instances.
+        final T rForestRoot = (T) beforeRotationFromOriginal.get(oForestRoot);
+        nOrphan = replaceDescendant(rotateFor, rForestRoot, (OperationClause) 
nOrphan, rTop);
+
+        return (T) nOrphan;
+    }
+
+    /** will return null instead of a leafClause **/
+    private <T extends OperationClause> T leftOpChild(final Class<T> opCls, 
final T clause){
+        final Clause c = leftChild(clause);
+        return c.getClass() == opCls ? (T) c : null;
+    }
+
+    /** return the left child, left or operation. **/
+    private Clause leftChild(final OperationClause clause) {
+        final Clause c = clause.getFirstClause();
+        return c;
+    }
+
+    /** will return null instead of a leafClause **/
+    private <T extends OperationClause> T rightOpChild(final Class<T> opCls, 
final T clause){
+        final Clause c = rightChild(clause);
+        return c.getClass() == opCls ? (T) c : null;
+    }
+
+    /** will return right child, left or operation. **/
+    private Clause rightChild(final OperationClause clause) {
+        Clause c = null;
+        if (clause instanceof AndClause) {
+            c = ((AndClause) clause).getSecondClause();
+        }  else if (clause instanceof OrClause) {
+            c = ((OrClause) clause).getSecondClause();
+        }
+        return c;
+    }
+
+    /** return the parent operation clause of the given child.
+     * And the child must be a descendant of the root. **/
+    private <T extends OperationClause> T parent(final T root, final Clause 
child) {
+        return parentFinder.getParent(root, child);
+    }
+
+    private OperationClause replaceDescendant(
+            final Class<?extends OperationClause> opCls,
+            final OperationClause root,
+            final OperationClause newChild,
+            final OperationClause replacementFor){
+
+        OperationClause nC = newChild;
+        OperationClause rR = replacementFor;
+        while(root != rR){
+            rR = parent(root, rR);
+            nC = replaceOperatorClause((Class<OperationClause>)opCls, nC, rR);
+        }
+        return nC;
+    }
+
+    private <T extends OperationClause> T replaceOperatorClause(
+            final Class<T> opCls,
+            final Clause newChild,
+            final T replacementFor) {
+
+        return createOperatorClause(opCls,
+                    leftChild(replacementFor) instanceof LeafClause ? 
leftChild(replacementFor) : newChild,
+                    rightChild(replacementFor) instanceof LeafClause ? 
rightChild(replacementFor) : newChild,
+                    replacementFor);
+    }
+
+    /** Create a new operator clause, of type opCls, with the left and right 
children.
+     * We must also specify for whom it is to be a replacement for.
+     * The replacementFor must be from the original branch.
+     **/
+    private <T extends OperationClause> T createOperatorClause(
+            final Class<T> opCls,
+            final Clause left,
+            final Clause right,
+            final T replacementFor) {
+
+        LOG.debug("createOperatorClause(" + ", " + left + ", " + right + ", " 
+ replacementFor + ")");
+        final T clause = (T) context.createAndClause(left, right); // FIXME 
And || Or
+        // update our mappings between rotations
+        originalFromNew.put(clause, replacementFor);
+        newFromOriginal.put(replacementFor, clause);
+        beforeRotationFromNew.put(clause, 
beforeRotationFromOriginal.get(replacementFor));
+
+        return clause;
+    }
+
+    private XorClause createXorClause(final OperationClause oRoot, final 
LinkedList<? extends OperationClause> rotations){
+
+
+        return context.createXorClause(
+                rotations.removeFirst(),
+                rotations.isEmpty() ? oRoot : createXorClause(oRoot, 
rotations),
+                XorClause.ROTATION_ALTERNATION);
+    }
+
+    // Inner classes -------------------------------------------------
+
+    private static final class ParentFinder extends AbstractReflectionVisitor {
+        private boolean searching = true;
+        private OperationClause parent;
+        private Clause child;
+
+        private static final String ERR_CANNOT_CALL_VISIT_DIRECTLY
+                = "visit(object) can't be called directly on this visitor!";
+        private static final String ERR_CHILD_NOT_IN_HEIRARCHY
+                = "The child is not part of this clause family!";
+
+        public synchronized <T extends OperationClause> T getParent(final T 
root, final Clause child) {
+            this.child = child;
+            visit(root);
+            this.child = null;
+            if (parent == null) {
+                throw new IllegalArgumentException(ERR_CHILD_NOT_IN_HEIRARCHY);
+            }
+            return (T)parent;
+        }
+
+
+        protected void visitImpl(final OperationClause clause) {
+            if (parent == null) {
+                if (clause.getFirstClause() == child) {
+                    parent = clause;
+                }  else  {
+                    clause.getFirstClause().accept(this);
+                }
+            }
+        }
+
+        protected void visitImpl(final OrClause clause) {
+            if (parent == null) {
+                if (clause.getFirstClause() == child || 
clause.getSecondClause() == child) {
+                    parent = clause;
+                }  else  {
+                    clause.getFirstClause().accept(this);
+                    clause.getSecondClause().accept(this);
+                }
+            }
+        }
+
+        protected void visitImpl(final AndClause clause) {
+            if (parent == null) {
+                if (clause.getFirstClause() == child || 
clause.getSecondClause() == child) {
+                    parent = clause;
+                }  else  {
+                    clause.getFirstClause().accept(this);
+                    clause.getSecondClause().accept(this);
+                }
+            }
+        }
+
+        protected void visitImpl(final DefaultOperatorClause clause) {
+            if (parent == null) {
+                if (clause.getFirstClause() == child || 
clause.getSecondClause() == child) {
+                    parent = clause;
+                }  else  {
+                    clause.getFirstClause().accept(this);
+                    clause.getSecondClause().accept(this);
+                }
+            }
+        }
+
+        protected void visitImpl(final LeafClause clause) {
+            // leaves can't be parents :-)
+        }
+
+        /**
+         * [EMAIL PROTECTED]
+         */
+        public void visit(final Object clause) {
+            if (searching || child == null) {
+                throw new 
IllegalStateException(ERR_CANNOT_CALL_VISIT_DIRECTLY);
+            }
+            searching = true;
+            super.visit(clause);
+            searching = false;
+        }
+
+    }
+
+    private static final class ForestFinder extends AbstractReflectionVisitor {
+        private boolean searching = true;
+        private final Set<OperationClause> roots = new 
HashSet<OperationClause>();
+
+        private static final String ERR_CANNOT_CALL_VISIT_DIRECTLY
+                = "visit(object) can't be called directly on this visitor!";
+
+        public synchronized Set<OperationClause> findForestRoots(final 
OperationClause root) {
+
+            visit(root);
+            roots.clear();
+            return Collections.unmodifiableSet(roots);
+        }
+
+
+        protected void visitImpl(final OperationClause clause) {
+
+            clause.getFirstClause().accept(this);
+        }
+
+        protected void visitImpl(final XorClause clause) {
+
+            clause.getFirstClause().accept(this);
+            clause.getSecondClause().accept(this);
+        }
+
+        protected void visitImpl(final OrClause clause) {
+
+            int count = 0;
+            for( OrClause or = clause;
+                    or.getSecondClause() instanceof OrClause;
+                    or = (OrClause) or.getSecondClause()){
+
+                ++count;
+            }
+            if(count >=3){
+                roots.add(clause);
+            }
+            clause.getFirstClause().accept(this);
+            clause.getSecondClause().accept(this);
+        }
+
+        protected void visitImpl(final AndClause clause) {
+            int count = 0;
+            for( AndClause or = clause;
+                    or.getSecondClause() instanceof AndClause;
+                    or = (AndClause) or.getSecondClause()){
+
+                ++count;
+            }
+            if(count >=3){
+                roots.add(clause);
+            }
+            clause.getFirstClause().accept(this);
+            clause.getSecondClause().accept(this);
+        }
+
+        protected void visitImpl(final DefaultOperatorClause clause) {
+            int count = 0;
+            for( DefaultOperatorClause or = clause;
+                    or.getSecondClause() instanceof DefaultOperatorClause;
+                    or = (DefaultOperatorClause) or.getSecondClause()){
+
+                ++count;
+            }
+            if(count >=3){
+                roots.add(clause);
+            }
+            clause.getFirstClause().accept(this);
+            clause.getSecondClause().accept(this);
+        }
+
+        protected void visitImpl(final LeafClause clause) {
+            // leaves can't be forest roots :-)
+        }
+
+        /**
+         * [EMAIL PROTECTED]
+         */
+        public void visit(final Object clause) {
+            if (searching) {
+                throw new 
IllegalStateException(ERR_CANNOT_CALL_VISIT_DIRECTLY);
+            }
+            searching = true;
+            super.visit(clause);
+            searching = false;
+        }
+
+    }
+
+}

_______________________________________________
Kernel-commits mailing list
[email protected]
http://sesat.no/mailman/listinfo/kernel-commits

Reply via email to