org.eclipse.viatra.query.runtime.localsearch.planner.LocalSearchPlanner.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.viatra.query.runtime.localsearch.planner.LocalSearchPlanner.java

Source

/*******************************************************************************
 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Marton Bur - initial API and implementation
 *******************************************************************************/
package org.eclipse.viatra.query.runtime.localsearch.planner;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation;
import org.eclipse.viatra.query.runtime.localsearch.planner.util.SearchPlanForBody;
import org.eclipse.viatra.query.runtime.matchers.context.IQueryMetaContext;
import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext;
import org.eclipse.viatra.query.runtime.matchers.planning.QueryProcessingException;
import org.eclipse.viatra.query.runtime.matchers.planning.SubPlan;
import org.eclipse.viatra.query.runtime.matchers.psystem.PBody;
import org.eclipse.viatra.query.runtime.matchers.psystem.PConstraint;
import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable;
import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PDisjunction;
import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery;
import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.PBodyNormalizer;
import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.PQueryFlattener;
import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.RewriterException;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * 
 * @author Marton Bur
 *
 */
public class LocalSearchPlanner {

    // Fields to track and debug the workflow
    // Internal data
    private PDisjunction flatDisjunction;
    private PDisjunction normalizedDisjunction;
    private List<SearchPlanForBody> plansForBodies;

    public PDisjunction getFlatDisjunction() {
        return flatDisjunction;
    }

    public PDisjunction getNormalizedDisjunction() {
        return normalizedDisjunction;
    }

    public List<SubPlan> getPlansForBodies() {
        return Lists.transform(plansForBodies, new Function<SearchPlanForBody, SubPlan>() {

            @Override
            public SubPlan apply(SearchPlanForBody input) {
                return input.getPlan();
            }
        });
    }

    // Externally set tools for planning
    private PQueryFlattener flattener;
    private LocalSearchRuntimeBasedStrategy plannerStrategy;
    private PBodyNormalizer normalizer;
    private POperationCompiler operationCompiler;
    private Logger logger;
    private IQueryMetaContext metaContext;
    private IQueryRuntimeContext runtimeContext;
    private Map<String, Object> hints;

    public void initializePlanner(PQueryFlattener pQueryFlattener, Logger logger, IQueryMetaContext metaContext,
            IQueryRuntimeContext runtimeContext, PBodyNormalizer pBodyNormalizer,
            LocalSearchRuntimeBasedStrategy localSearchPlannerStrategy, POperationCompiler pOperationCompiler,
            Map<String, Object> hints) {
        this.flattener = pQueryFlattener;
        this.logger = logger;
        this.metaContext = metaContext;
        this.runtimeContext = runtimeContext;
        this.normalizer = pBodyNormalizer;
        this.plannerStrategy = localSearchPlannerStrategy;
        this.operationCompiler = pOperationCompiler;
        this.hints = hints;
    }

    /**
     * Creates executable plans for the provided query. It is required to call one of the
     * <code>initializePlanner()</code> methods before calling this method.
     * 
     * @param querySpec
     * @param boundVarIndices
     *            a set of integers representing the variables that are bound
     * @return a mapping between ISearchOperation list and a mapping, that holds a PVariable-Integer mapping for the
     *         list of ISearchOperations
     * @throws QueryProcessingException
     */
    public Collection<SearchPlanForBody> plan(PQuery querySpec, Set<Integer> boundVarIndices)
            throws QueryProcessingException {

        // 1. Preparation
        Set<PBody> normalizedBodies = prepareNormalizedBodies(querySpec);

        plansForBodies = Lists.newArrayListWithExpectedSize(normalizedBodies.size());

        for (PBody normalizedBody : normalizedBodies) {
            // 2. Plan creation
            // Context has matchers for the referred Queries (IQuerySpecifications)
            Set<PVariable> boundVariables = calculatePatternAdornmentForPlanner(boundVarIndices, normalizedBody);
            SubPlan plan = plannerStrategy.plan(normalizedBody, logger, boundVariables, metaContext, runtimeContext,
                    hints);
            // 3. PConstraint -> POperation compilation step
            // TODO finish (revisit?) the implementation of the compile function
            // * Pay extra caution to extend operations, when more than one variables are unbound
            List<ISearchOperation> compiledOperations = operationCompiler.compile(plan, boundVarIndices);
            // Store the variable mappings for the plans for debug purposes (traceability information)
            SearchPlanForBody compiledPlan = new SearchPlanForBody(normalizedBody,
                    operationCompiler.getVariableMappings(), plan, compiledOperations);

            plansForBodies.add(compiledPlan);
        }

        return plansForBodies;
    }

    private Set<PBody> prepareNormalizedBodies(PQuery querySpec) throws RewriterException {
        // Preparation steps
        // Flatten
        flatDisjunction = flattener.rewrite(querySpec.getDisjunctBodies());
        Set<PBody> flatBodies = flatDisjunction.getBodies();
        prepareFlatBodiesForNormalize(flatBodies);

        // Normalize
        normalizedDisjunction = normalizer.rewrite(flatDisjunction);
        Set<PBody> normalizedBodies = normalizedDisjunction.getBodies();

        removeDuplicateConstraints(normalizedBodies);

        return normalizedBodies;
    }

    private void removeDuplicateConstraints(Set<PBody> normalizedBodies) {
        for (PBody pBody : normalizedBodies) {
            pBody.setStatus(PQueryStatus.UNINITIALIZED);
            Set<PConstraint> constraintsToRemove = Sets.newHashSet();
            Set<PConstraint> duplicateConstraints = Sets.newHashSet();
            Set<PConstraint> constraints = pBody.getConstraints();
            for (PConstraint pConstraint1 : constraints) {
                for (PConstraint pConstraint2 : constraints) {
                    if (!constraintsToRemove.contains(pConstraint2)
                            && pConstraint1.toString().equals(pConstraint2.toString())) {
                        duplicateConstraints.add(pConstraint1);
                        constraintsToRemove.add(pConstraint1);
                        constraintsToRemove.add(pConstraint2);
                    }
                }
            }
            for (PConstraint pConstraint : constraintsToRemove) {
                pBody.getConstraints().remove(pConstraint);
            }
            for (PConstraint pConstraint : duplicateConstraints) {
                pBody.getConstraints().add(pConstraint);
            }
            pBody.setStatus(PQueryStatus.OK);
        }
    }

    private void prepareFlatBodiesForNormalize(Set<PBody> flatBodies) {
        // Revert status to be able to rewrite
        // XXX Needed because the current implementation of the Normalizer requires mutable bodies
        for (PBody pBody : flatBodies) {
            pBody.setStatus(PQueryStatus.UNINITIALIZED);
        }
    }

    private Set<PVariable> calculatePatternAdornmentForPlanner(Set<Integer> boundVarIndices, PBody normalizedBody) {
        Set<PVariable> boundVariables = Sets.<PVariable>newHashSet();
        for (Integer i : boundVarIndices) {
            boundVariables.add(normalizedBody.getSymbolicParameterVariables().get(i));
        }
        return boundVariables;
    }

}